From f56bb35301836e56582a575a75864392a0177875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20P=2E=20Tjern=C3=B8?= Date: Mon, 2 Dec 2013 19:31:46 -0800 Subject: Fix line endings. WHAMMY. --- mp/src/public/chunkfile.cpp | 1970 +++++++++++++++++++++---------------------- 1 file changed, 985 insertions(+), 985 deletions(-) (limited to 'mp/src/public/chunkfile.cpp') diff --git a/mp/src/public/chunkfile.cpp b/mp/src/public/chunkfile.cpp index 6554ed09..81a77dd3 100644 --- a/mp/src/public/chunkfile.cpp +++ b/mp/src/public/chunkfile.cpp @@ -1,985 +1,985 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: Implements an interface for reading and writing heirarchical -// text files of key value pairs. The format of the file is as follows: -// -// chunkname0 -// { -// "key0" "value0" -// "key1" "value1" -// ... -// "keyN" "valueN" -// chunkname1 -// { -// "key0" "value0" -// "key1" "value1" -// ... -// "keyN" "valueN" -// } -// } -// ... -// chunknameN -// { -// "key0" "value0" -// "key1" "value1" -// ... -// "keyN" "valueN" -// } -// -// The chunk names are not necessarily unique, nor are the key names, unless the -// parsing application requires them to be. -// -// $NoKeywords: $ -//=============================================================================// - -#include -#ifdef _WIN32 -#include -#endif -#include -#include -#include -#include -#include -#include "chunkfile.h" -#include "mathlib/vector.h" -#include "mathlib/vector4d.h" -#include "tier1/strtools.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - - -//----------------------------------------------------------------------------- -// Purpose: Constructor. -//----------------------------------------------------------------------------- -CChunkHandlerMap::CChunkHandlerMap(void) -{ - m_pHandlers = NULL; -} - - -//----------------------------------------------------------------------------- -// Purpose: Destructor. Frees handler list. -//----------------------------------------------------------------------------- -CChunkHandlerMap::~CChunkHandlerMap(void) -{ - ChunkHandlerInfoNode_t *pNode = m_pHandlers; - while (pNode != NULL) - { - ChunkHandlerInfoNode_t *pPrev = pNode; - pNode = pNode->pNext; - - delete pPrev; - } -} - - -//----------------------------------------------------------------------------- -// Purpose: Adds a chunk handler to the handler list. -// Input : pszChunkName - Name of chunk to be handled. -// pfnHandler - Address of handler callback function. -// pData - Data to pass to the handler callback. -//----------------------------------------------------------------------------- -void CChunkHandlerMap::AddHandler(const char *pszChunkName, ChunkHandler_t pfnHandler, void *pData) -{ - ChunkHandlerInfoNode_t *pNew = new ChunkHandlerInfoNode_t; - - Q_strncpy(pNew->Handler.szChunkName, pszChunkName, sizeof( pNew->Handler.szChunkName )); - pNew->Handler.pfnHandler = pfnHandler; - pNew->Handler.pData = pData; - pNew->pNext = NULL; - - if (m_pHandlers == NULL) - { - m_pHandlers = pNew; - } - else - { - ChunkHandlerInfoNode_t *pNode = m_pHandlers; - while (pNode->pNext != NULL) - { - pNode = pNode->pNext; - } - pNode->pNext = pNew; - } -} - - -//----------------------------------------------------------------------------- -// Purpose: Sets the callback for error handling within this chunk's scope. -// Input : pfnHandler - -// pData - -//----------------------------------------------------------------------------- -void CChunkHandlerMap::SetErrorHandler(ChunkErrorHandler_t pfnHandler, void *pData) -{ - m_pfnErrorHandler = pfnHandler; - m_pErrorData = pData; -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : ppData - -// Output : ChunkErrorHandler_t -//----------------------------------------------------------------------------- -ChunkErrorHandler_t CChunkHandlerMap::GetErrorHandler(void **ppData) -{ - *ppData = m_pErrorData; - return(m_pfnErrorHandler); -} - - -//----------------------------------------------------------------------------- -// Purpose: Gets the handler for a given chunk name, if one has been set. -// Input : pszChunkName - Name of chunk. -// ppfnHandler - Receives the address of the callback function. -// ppData - Receives the context data for the given chunk. -// Output : Returns true if a handler was found, false if not. -//----------------------------------------------------------------------------- -ChunkHandler_t CChunkHandlerMap::GetHandler(const char *pszChunkName, void **ppData) -{ - ChunkHandlerInfoNode_t *pNode = m_pHandlers; - while (pNode != NULL) - { - if (!stricmp(pNode->Handler.szChunkName, pszChunkName)) - { - *ppData = pNode->Handler.pData; - return(pNode->Handler.pfnHandler); - } - - pNode = pNode->pNext; - } - - return(false); -} - - -//----------------------------------------------------------------------------- -// Purpose: Constructor. Initializes data members. -//----------------------------------------------------------------------------- -CChunkFile::CChunkFile(void) -{ - m_hFile = NULL; - m_nCurrentDepth = 0; - m_szIndent[0] = '\0'; - m_nHandlerStackDepth = 0; - m_DefaultChunkHandler = 0; -} - - -//----------------------------------------------------------------------------- -// Purpose: Destructor. Closes the file if it is currently open. -//----------------------------------------------------------------------------- -CChunkFile::~CChunkFile(void) -{ - if (m_hFile != NULL) - { - fclose(m_hFile); - } -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *pszChunkName - -// Output : ChunkFileResult_t -//----------------------------------------------------------------------------- -ChunkFileResult_t CChunkFile::BeginChunk(const char *pszChunkName) -{ - // - // Write the chunk name and open curly. - // - char szBuf[MAX_KEYVALUE_LEN]; - Q_snprintf(szBuf, sizeof( szBuf ), "%s\r\n%s{", pszChunkName, m_szIndent); - ChunkFileResult_t eResult = WriteLine(szBuf); - - // - // Update the indentation depth. - // - if (eResult == ChunkFile_Ok) - { - m_nCurrentDepth++; - BuildIndentString(m_szIndent, m_nCurrentDepth); - } - - return(eResult); -} - - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CChunkFile::BuildIndentString(char *pszDest, int nDepth) -{ - if (nDepth >= 0) - { - for (int i = 0; i < nDepth; i++) - { - pszDest[i] = '\t'; - } - - pszDest[nDepth] = '\0'; - } -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Output : ChunkFileResult_t -//----------------------------------------------------------------------------- -ChunkFileResult_t CChunkFile::Close(void) -{ - if (m_hFile != NULL) - { - fclose(m_hFile); - m_hFile = NULL; - } - - return(ChunkFile_Ok); -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Output : ChunkFileResult_t -//----------------------------------------------------------------------------- -ChunkFileResult_t CChunkFile::EndChunk(void) -{ - if (m_nCurrentDepth > 0) - { - m_nCurrentDepth--; - BuildIndentString(m_szIndent, m_nCurrentDepth); - } - - WriteLine("}"); - - return(ChunkFile_Ok); -} - - -//----------------------------------------------------------------------------- -// Purpose: Returns a string explaining the last error that occurred. -//----------------------------------------------------------------------------- -const char *CChunkFile::GetErrorText(ChunkFileResult_t eResult) -{ - static char szError[MAX_KEYVALUE_LEN]; - - switch (eResult) - { - case ChunkFile_UnexpectedEOF: - { - Q_strncpy(szError, "unexpected end of file", sizeof( szError ) ); - break; - } - - case ChunkFile_UnexpectedSymbol: - { - Q_snprintf(szError, sizeof( szError ), "unexpected symbol '%s'", m_szErrorToken); - break; - } - - case ChunkFile_OpenFail: - { - Q_snprintf(szError, sizeof( szError ), "%s", strerror(errno)) ; - break; - } - - case ChunkFile_StringTooLong: - { - Q_strncpy(szError, "unterminated string or string too long", sizeof( szError ) ); - break; - } - - default: - { - Q_snprintf(szError, sizeof( szError ), "error %d", eResult); - } - } - - return(m_TokenReader.Error(szError)); -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : eError - -//----------------------------------------------------------------------------- -void CChunkFile::HandleError(const char *szChunkName, ChunkFileResult_t eError) -{ - // UNDONE: dispatch errors to the error handler. - // - keep track of current chunkname for reporting errors - // - use the last non-NULL handler that was pushed onto the stack? - // - need a return code to determine whether to abort parsing? -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Output : ChunkFileResult_t -//----------------------------------------------------------------------------- -ChunkFileResult_t CChunkFile::HandleChunk(const char *szChunkName) -{ - // See if the default handler wants it? - if( m_DefaultChunkHandler ) - { - ChunkFileResult_t testResult = m_DefaultChunkHandler( this, m_pDefaultChunkHandlerData, szChunkName ); - if( testResult == ChunkFile_Ok ) - { - return ChunkFile_Ok; - } - } - - // - // If there is an active handler map... - // - if (m_nHandlerStackDepth > 0) - { - CChunkHandlerMap *pHandler = m_HandlerStack[m_nHandlerStackDepth - 1]; - - // - // If a chunk handler was found in the handler map... - // - void *pData; - ChunkHandler_t pfnHandler = pHandler->GetHandler(szChunkName, &pData); - if (pfnHandler != NULL) - { - // Dispatch this chunk to the handler. - ChunkFileResult_t eResult = pfnHandler(this, pData); - if (eResult != ChunkFile_Ok) - { - return(eResult); - } - } - else - { - // - // No handler for this chunk. Skip to the matching close curly brace. - // - int nDepth = 1; - ChunkFileResult_t eResult; - - do - { - ChunkType_t eChunkType; - char szKey[MAX_KEYVALUE_LEN]; - char szValue[MAX_KEYVALUE_LEN]; - - while ((eResult = ReadNext(szKey, szValue, sizeof(szValue), eChunkType)) == ChunkFile_Ok) - { - if (eChunkType == ChunkType_Chunk) - { - nDepth++; - } - } - - if (eResult == ChunkFile_EndOfChunk) - { - eResult = ChunkFile_Ok; - nDepth--; - } - else if (eResult == ChunkFile_EOF) - { - return(ChunkFile_UnexpectedEOF); - } - - } while ((nDepth) && (eResult == ChunkFile_Ok)); - } - } - - return(ChunkFile_Ok); -} - - -//----------------------------------------------------------------------------- -// Purpose: Opens the chunk file for reading or writing. -// Input : pszFileName - Path of file to open. -// eMode - ChunkFile_Read or ChunkFile_Write. -// Output : Returns ChunkFile_Ok on success, ChunkFile_Fail on failure. -// UNDONE: boolean return value? -//----------------------------------------------------------------------------- -ChunkFileResult_t CChunkFile::Open(const char *pszFileName, ChunkFileOpenMode_t eMode) -{ - if (eMode == ChunkFile_Read) - { - // UNDONE: TokenReader encapsulates file - unify reading and writing to use the same file I/O. - // UNDONE: Support in-memory parsing. - if (m_TokenReader.Open(pszFileName)) - { - m_nCurrentDepth = 0; - } - else - { - return(ChunkFile_OpenFail); - } - } - else if (eMode == ChunkFile_Write) - { - m_hFile = fopen(pszFileName, "wb"); - - if (m_hFile == NULL) - { - return(ChunkFile_OpenFail); - } - - m_nCurrentDepth = 0; - } - - return(ChunkFile_Ok); -} - - -//----------------------------------------------------------------------------- -// Purpose: Removes the topmost set of chunk handlers. -//----------------------------------------------------------------------------- -void CChunkFile::PopHandlers(void) -{ - if (m_nHandlerStackDepth > 0) - { - m_nHandlerStackDepth--; - } -} - - -void CChunkFile::SetDefaultChunkHandler( DefaultChunkHandler_t pHandler, void *pData ) -{ - m_DefaultChunkHandler = pHandler; - m_pDefaultChunkHandlerData = pData;} - - -//----------------------------------------------------------------------------- -// Purpose: Adds a set of chunk handlers to the top of the handler stack. -// Input : pHandlerMap - Object containing the list of chunk handlers. -//----------------------------------------------------------------------------- -void CChunkFile::PushHandlers(CChunkHandlerMap *pHandlerMap) -{ - if (m_nHandlerStackDepth < MAX_INDENT_DEPTH) - { - m_HandlerStack[m_nHandlerStackDepth] = pHandlerMap; - m_nHandlerStackDepth++; - } -} - - -//----------------------------------------------------------------------------- -// Purpose: Reads the next term from the chunk file. The type of term read is -// returned in the eChunkType parameter. -// Input : szName - Name of key or chunk. -// szValue - If eChunkType is ChunkType_Key, contains the value of the key. -// nValueSize - Size of the buffer pointed to by szValue. -// eChunkType - ChunkType_Key or ChunkType_Chunk. -// Output : Returns ChunkFile_Ok on success, an error code if a parsing error occurs. -//----------------------------------------------------------------------------- -ChunkFileResult_t CChunkFile::ReadNext(char *szName, char *szValue, int nValueSize, ChunkType_t &eChunkType) -{ - // HACK: pass in buffer sizes? - trtoken_t eTokenType = m_TokenReader.NextToken(szName, MAX_KEYVALUE_LEN); - - if (eTokenType != TOKENEOF) - { - switch (eTokenType) - { - case IDENT: - case STRING: - { - char szNext[MAX_KEYVALUE_LEN]; - trtoken_t eNextTokenType; - - // - // Read the next token to determine what we have. - // - eNextTokenType = m_TokenReader.NextToken(szNext, sizeof(szNext)); - - switch (eNextTokenType) - { - case OPERATOR: - { - if (!stricmp(szNext, "{")) - { - // Beginning of new chunk. - m_nCurrentDepth++; - eChunkType = ChunkType_Chunk; - szValue[0] = '\0'; - return(ChunkFile_Ok); - } - else - { - // Unexpected symbol. - Q_strncpy(m_szErrorToken, szNext, sizeof( m_szErrorToken ) ); - return(ChunkFile_UnexpectedSymbol); - } - } - - case STRING: - case IDENT: - { - // Key value pair. - Q_strncpy(szValue, szNext, nValueSize ); - eChunkType = ChunkType_Key; - return(ChunkFile_Ok); - } - - case TOKENEOF: - { - // Unexpected end of file. - return(ChunkFile_UnexpectedEOF); - } - - case TOKENSTRINGTOOLONG: - { - // String too long or unterminated string. - return ChunkFile_StringTooLong; - } - } - } - - case OPERATOR: - { - if (!stricmp(szName, "}")) - { - // End of current chunk. - m_nCurrentDepth--; - return(ChunkFile_EndOfChunk); - } - else - { - // Unexpected symbol. - Q_strncpy(m_szErrorToken, szName, sizeof( m_szErrorToken ) ); - return(ChunkFile_UnexpectedSymbol); - } - } - - case TOKENSTRINGTOOLONG: - { - return ChunkFile_StringTooLong; - } - } - } - - if (m_nCurrentDepth != 0) - { - // End of file while within the scope of a chunk. - return(ChunkFile_UnexpectedEOF); - } - - return(ChunkFile_EOF); -} - - -//----------------------------------------------------------------------------- -// Purpose: Reads the current chunk and dispatches keys and sub-chunks to the -// appropriate handler callbacks. -// Input : pfnKeyHandler - Callback for any key values in this chunk. -// pData - Data to pass to the key value callback function. -// Output : Normally returns ChunkFile_Ok or ChunkFile_EOF. Otherwise, returns -// a ChunkFile_xxx error code. -//----------------------------------------------------------------------------- -ChunkFileResult_t CChunkFile::ReadChunk(KeyHandler_t pfnKeyHandler, void *pData) -{ - // - // Read the keys and sub-chunks. - // - ChunkFileResult_t eResult; - do - { - char szName[MAX_KEYVALUE_LEN]; - char szValue[MAX_KEYVALUE_LEN]; - ChunkType_t eChunkType; - - eResult = ReadNext(szName, szValue, sizeof(szValue), eChunkType); - - if (eResult == ChunkFile_Ok) - { - if (eChunkType == ChunkType_Chunk) - { - // - // Dispatch sub-chunks to the appropriate handler. - // - eResult = HandleChunk(szName); - } - else if ((eChunkType == ChunkType_Key) && (pfnKeyHandler != NULL)) - { - // - // Dispatch keys to the key value handler. - // - eResult = pfnKeyHandler(szName, szValue, pData); - } - } - } while (eResult == ChunkFile_Ok); - - // - // Cover up ChunkFile_EndOfChunk results because the caller doesn't want to see them. - // - if (eResult == ChunkFile_EndOfChunk) - { - eResult = ChunkFile_Ok; - } - - // - // Dispatch errors to the handler. - // - if ((eResult != ChunkFile_Ok) && (eResult != ChunkFile_EOF)) - { - //HandleError("chunkname", eResult); - } - - return(eResult); -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : pszValue - -// pbBool - -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CChunkFile::ReadKeyValueBool(const char *pszValue, bool &bBool) -{ - int nValue = atoi(pszValue); - - if (nValue > 0) - { - bBool = true; - } - else - { - bBool = false; - } - - return(true); -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : pszValue - -// pfFloat - -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CChunkFile::ReadKeyValueFloat(const char *pszValue, float &flFloat) -{ - flFloat = (float)atof(pszValue); - return(true); -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : pszValue - -// pnInt - -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CChunkFile::ReadKeyValueInt(const char *pszValue, int &nInt) -{ - nInt = atoi(pszValue); - return(true); -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : pszKey - -// r - -// g - -// b - -// Output : -//----------------------------------------------------------------------------- -bool CChunkFile::ReadKeyValueColor(const char *pszValue, unsigned char &chRed, unsigned char &chGreen, unsigned char &chBlue) -{ - if (pszValue != NULL) - { - int r = 0; - int g = 0; - int b = 0; - - if (sscanf(pszValue, "%d %d %d", &r, &g, &b) == 3) - { - chRed = r; - chGreen = g; - chBlue = b; - - return(true); - } - } - - return(false); -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : pszValue - -// pfPoint - -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CChunkFile::ReadKeyValuePoint(const char *pszValue, Vector &Point) -{ - if (pszValue != NULL) - { - return(sscanf(pszValue, "(%f %f %f)", &Point.x, &Point.y, &Point.z) == 3); - } - - return(false); -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : pszValue - -// pfVector - -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CChunkFile::ReadKeyValueVector2(const char *pszValue, Vector2D &vec) -{ - if (pszValue != NULL) - { - return ( sscanf( pszValue, "[%f %f]", &vec.x, &vec.y) == 2 ); - } - - return(false); -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : pszValue - -// pfVector - -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CChunkFile::ReadKeyValueVector3(const char *pszValue, Vector &vec) -{ - if (pszValue != NULL) - { - return(sscanf(pszValue, "[%f %f %f]", &vec.x, &vec.y, &vec.z) == 3); - } - - return(false); -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : pszValue - -// pfVector - -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CChunkFile::ReadKeyValueVector4(const char *pszValue, Vector4D &vec) -{ - if( pszValue != NULL ) - { - return(sscanf(pszValue, "[%f %f %f %f]", &vec[0], &vec[1], &vec[2], &vec[3]) == 4); - } - - return false; -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : pszLine - -// Output : -//----------------------------------------------------------------------------- -ChunkFileResult_t CChunkFile::WriteKeyValue(const char *pszKey, const char *pszValue) -{ - if ((pszKey != NULL) && (pszValue != NULL)) - { - char szTemp[MAX_KEYVALUE_LEN]; - Q_snprintf(szTemp, sizeof( szTemp ), "\"%s\" \"%s\"", pszKey, pszValue); - return(WriteLine(szTemp)); - } - - return(ChunkFile_Ok); -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : pszKey - -// bValue - -// Output : -//----------------------------------------------------------------------------- -ChunkFileResult_t CChunkFile::WriteKeyValueBool(const char *pszKey, bool bValue) -{ - if (pszKey != NULL) - { - char szBuf[MAX_KEYVALUE_LEN]; - Q_snprintf(szBuf, sizeof( szBuf ), "\"%s\" \"%d\"", pszKey, (int)bValue); - return(WriteLine(szBuf)); - } - - return(ChunkFile_Ok); -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : pszKey - -// nValue - -// Output : -//----------------------------------------------------------------------------- -ChunkFileResult_t CChunkFile::WriteKeyValueInt(const char *pszKey, int nValue) -{ - if (pszKey != NULL) - { - char szBuf[MAX_KEYVALUE_LEN]; - Q_snprintf(szBuf, sizeof( szBuf ), "\"%s\" \"%d\"", pszKey, nValue); - return(WriteLine(szBuf)); - } - - return(ChunkFile_Ok); -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : pszKey - -// fValue - -// Output : -//----------------------------------------------------------------------------- -ChunkFileResult_t CChunkFile::WriteKeyValueFloat(const char *pszKey, float fValue) -{ - if (pszKey != NULL) - { - char szBuf[MAX_KEYVALUE_LEN]; - Q_snprintf(szBuf, sizeof( szBuf ), "\"%s\" \"%g\"", pszKey, (double)fValue); - return(WriteLine(szBuf)); - } - - return(ChunkFile_Ok); -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : pszKey - -// r - -// g - -// b - -// Output : -//----------------------------------------------------------------------------- -ChunkFileResult_t CChunkFile::WriteKeyValueColor(const char *pszKey, unsigned char r, unsigned char g, unsigned char b) -{ - if (pszKey != NULL) - { - char szBuf[MAX_KEYVALUE_LEN]; - Q_snprintf(szBuf, sizeof( szBuf ), "\"%s\" \"%d %d %d\"", pszKey, (int)r, (int)g, (int)b); - return(WriteLine(szBuf)); - } - - return(ChunkFile_Ok); -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : pszKey - -// fVector - -// Output : -//----------------------------------------------------------------------------- -ChunkFileResult_t CChunkFile::WriteKeyValuePoint(const char *pszKey, const Vector &Point) -{ - if (pszKey != NULL) - { - char szBuf[MAX_KEYVALUE_LEN]; - Q_snprintf(szBuf, sizeof( szBuf ), "\"%s\" \"(%g %g %g)\"", pszKey, (double)Point[0], (double)Point[1], (double)Point[2]); - return(WriteLine(szBuf)); - } - - return(ChunkFile_Ok); -} - - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -ChunkFileResult_t CChunkFile::WriteKeyValueVector2(const char *pszKey, const Vector2D &vec) -{ - if (pszKey != NULL) - { - char szBuf[MAX_KEYVALUE_LEN]; - Q_snprintf( szBuf, sizeof( szBuf ), "\"%s\" \"[%g %g]\"", pszKey, (double)vec.x, (double)vec.y ); - return(WriteLine(szBuf)); - } - - return(ChunkFile_Ok); -} - - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -ChunkFileResult_t CChunkFile::WriteKeyValueVector3(const char *pszKey, const Vector &vec) -{ - if (pszKey != NULL) - { - char szBuf[MAX_KEYVALUE_LEN]; - Q_snprintf(szBuf, sizeof( szBuf ), "\"%s\" \"[%g %g %g]\"", pszKey, (double)vec.x, (double)vec.y, (double)vec.z); - return(WriteLine(szBuf)); - } - - return(ChunkFile_Ok); -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : pszKey - -// fVector - -// Output : -//----------------------------------------------------------------------------- -ChunkFileResult_t CChunkFile::WriteKeyValueVector4(const char *pszKey, const Vector4D &vec) -{ - if (pszKey != NULL) - { - char szBuf[MAX_KEYVALUE_LEN]; - Q_snprintf(szBuf, sizeof( szBuf ), "\"%s\" \"[%g %g %g %g]\"", pszKey, (double)vec.x, (double)vec.y, (double)vec.z, (double)vec.w); - return( WriteLine( szBuf ) ); - } - - return( ChunkFile_Ok ); -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *pszLine - -// Output : -//----------------------------------------------------------------------------- -ChunkFileResult_t CChunkFile::WriteLine(const char *pszLine) -{ - if (pszLine != NULL) - { - // - // Write the indentation string. - // - if (m_nCurrentDepth > 0) - { - int nWritten = fwrite(m_szIndent, 1, m_nCurrentDepth, m_hFile); - if (nWritten != m_nCurrentDepth) - { - return(ChunkFile_Fail); - } - } - - // - // Write the string. - // - int nLen = strlen(pszLine); - int nWritten = fwrite(pszLine, 1, nLen, m_hFile); - if (nWritten != nLen) - { - return(ChunkFile_Fail); - } - - // - // Write the linefeed. - // - if (fwrite("\r\n", 1, 2, m_hFile) != 2) - { - return(ChunkFile_Fail); - } - } - - return(ChunkFile_Ok); -} - +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Implements an interface for reading and writing heirarchical +// text files of key value pairs. The format of the file is as follows: +// +// chunkname0 +// { +// "key0" "value0" +// "key1" "value1" +// ... +// "keyN" "valueN" +// chunkname1 +// { +// "key0" "value0" +// "key1" "value1" +// ... +// "keyN" "valueN" +// } +// } +// ... +// chunknameN +// { +// "key0" "value0" +// "key1" "value1" +// ... +// "keyN" "valueN" +// } +// +// The chunk names are not necessarily unique, nor are the key names, unless the +// parsing application requires them to be. +// +// $NoKeywords: $ +//=============================================================================// + +#include +#ifdef _WIN32 +#include +#endif +#include +#include +#include +#include +#include +#include "chunkfile.h" +#include "mathlib/vector.h" +#include "mathlib/vector4d.h" +#include "tier1/strtools.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +//----------------------------------------------------------------------------- +// Purpose: Constructor. +//----------------------------------------------------------------------------- +CChunkHandlerMap::CChunkHandlerMap(void) +{ + m_pHandlers = NULL; +} + + +//----------------------------------------------------------------------------- +// Purpose: Destructor. Frees handler list. +//----------------------------------------------------------------------------- +CChunkHandlerMap::~CChunkHandlerMap(void) +{ + ChunkHandlerInfoNode_t *pNode = m_pHandlers; + while (pNode != NULL) + { + ChunkHandlerInfoNode_t *pPrev = pNode; + pNode = pNode->pNext; + + delete pPrev; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Adds a chunk handler to the handler list. +// Input : pszChunkName - Name of chunk to be handled. +// pfnHandler - Address of handler callback function. +// pData - Data to pass to the handler callback. +//----------------------------------------------------------------------------- +void CChunkHandlerMap::AddHandler(const char *pszChunkName, ChunkHandler_t pfnHandler, void *pData) +{ + ChunkHandlerInfoNode_t *pNew = new ChunkHandlerInfoNode_t; + + Q_strncpy(pNew->Handler.szChunkName, pszChunkName, sizeof( pNew->Handler.szChunkName )); + pNew->Handler.pfnHandler = pfnHandler; + pNew->Handler.pData = pData; + pNew->pNext = NULL; + + if (m_pHandlers == NULL) + { + m_pHandlers = pNew; + } + else + { + ChunkHandlerInfoNode_t *pNode = m_pHandlers; + while (pNode->pNext != NULL) + { + pNode = pNode->pNext; + } + pNode->pNext = pNew; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Sets the callback for error handling within this chunk's scope. +// Input : pfnHandler - +// pData - +//----------------------------------------------------------------------------- +void CChunkHandlerMap::SetErrorHandler(ChunkErrorHandler_t pfnHandler, void *pData) +{ + m_pfnErrorHandler = pfnHandler; + m_pErrorData = pData; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : ppData - +// Output : ChunkErrorHandler_t +//----------------------------------------------------------------------------- +ChunkErrorHandler_t CChunkHandlerMap::GetErrorHandler(void **ppData) +{ + *ppData = m_pErrorData; + return(m_pfnErrorHandler); +} + + +//----------------------------------------------------------------------------- +// Purpose: Gets the handler for a given chunk name, if one has been set. +// Input : pszChunkName - Name of chunk. +// ppfnHandler - Receives the address of the callback function. +// ppData - Receives the context data for the given chunk. +// Output : Returns true if a handler was found, false if not. +//----------------------------------------------------------------------------- +ChunkHandler_t CChunkHandlerMap::GetHandler(const char *pszChunkName, void **ppData) +{ + ChunkHandlerInfoNode_t *pNode = m_pHandlers; + while (pNode != NULL) + { + if (!stricmp(pNode->Handler.szChunkName, pszChunkName)) + { + *ppData = pNode->Handler.pData; + return(pNode->Handler.pfnHandler); + } + + pNode = pNode->pNext; + } + + return(false); +} + + +//----------------------------------------------------------------------------- +// Purpose: Constructor. Initializes data members. +//----------------------------------------------------------------------------- +CChunkFile::CChunkFile(void) +{ + m_hFile = NULL; + m_nCurrentDepth = 0; + m_szIndent[0] = '\0'; + m_nHandlerStackDepth = 0; + m_DefaultChunkHandler = 0; +} + + +//----------------------------------------------------------------------------- +// Purpose: Destructor. Closes the file if it is currently open. +//----------------------------------------------------------------------------- +CChunkFile::~CChunkFile(void) +{ + if (m_hFile != NULL) + { + fclose(m_hFile); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pszChunkName - +// Output : ChunkFileResult_t +//----------------------------------------------------------------------------- +ChunkFileResult_t CChunkFile::BeginChunk(const char *pszChunkName) +{ + // + // Write the chunk name and open curly. + // + char szBuf[MAX_KEYVALUE_LEN]; + Q_snprintf(szBuf, sizeof( szBuf ), "%s\r\n%s{", pszChunkName, m_szIndent); + ChunkFileResult_t eResult = WriteLine(szBuf); + + // + // Update the indentation depth. + // + if (eResult == ChunkFile_Ok) + { + m_nCurrentDepth++; + BuildIndentString(m_szIndent, m_nCurrentDepth); + } + + return(eResult); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CChunkFile::BuildIndentString(char *pszDest, int nDepth) +{ + if (nDepth >= 0) + { + for (int i = 0; i < nDepth; i++) + { + pszDest[i] = '\t'; + } + + pszDest[nDepth] = '\0'; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Output : ChunkFileResult_t +//----------------------------------------------------------------------------- +ChunkFileResult_t CChunkFile::Close(void) +{ + if (m_hFile != NULL) + { + fclose(m_hFile); + m_hFile = NULL; + } + + return(ChunkFile_Ok); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Output : ChunkFileResult_t +//----------------------------------------------------------------------------- +ChunkFileResult_t CChunkFile::EndChunk(void) +{ + if (m_nCurrentDepth > 0) + { + m_nCurrentDepth--; + BuildIndentString(m_szIndent, m_nCurrentDepth); + } + + WriteLine("}"); + + return(ChunkFile_Ok); +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns a string explaining the last error that occurred. +//----------------------------------------------------------------------------- +const char *CChunkFile::GetErrorText(ChunkFileResult_t eResult) +{ + static char szError[MAX_KEYVALUE_LEN]; + + switch (eResult) + { + case ChunkFile_UnexpectedEOF: + { + Q_strncpy(szError, "unexpected end of file", sizeof( szError ) ); + break; + } + + case ChunkFile_UnexpectedSymbol: + { + Q_snprintf(szError, sizeof( szError ), "unexpected symbol '%s'", m_szErrorToken); + break; + } + + case ChunkFile_OpenFail: + { + Q_snprintf(szError, sizeof( szError ), "%s", strerror(errno)) ; + break; + } + + case ChunkFile_StringTooLong: + { + Q_strncpy(szError, "unterminated string or string too long", sizeof( szError ) ); + break; + } + + default: + { + Q_snprintf(szError, sizeof( szError ), "error %d", eResult); + } + } + + return(m_TokenReader.Error(szError)); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : eError - +//----------------------------------------------------------------------------- +void CChunkFile::HandleError(const char *szChunkName, ChunkFileResult_t eError) +{ + // UNDONE: dispatch errors to the error handler. + // - keep track of current chunkname for reporting errors + // - use the last non-NULL handler that was pushed onto the stack? + // - need a return code to determine whether to abort parsing? +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Output : ChunkFileResult_t +//----------------------------------------------------------------------------- +ChunkFileResult_t CChunkFile::HandleChunk(const char *szChunkName) +{ + // See if the default handler wants it? + if( m_DefaultChunkHandler ) + { + ChunkFileResult_t testResult = m_DefaultChunkHandler( this, m_pDefaultChunkHandlerData, szChunkName ); + if( testResult == ChunkFile_Ok ) + { + return ChunkFile_Ok; + } + } + + // + // If there is an active handler map... + // + if (m_nHandlerStackDepth > 0) + { + CChunkHandlerMap *pHandler = m_HandlerStack[m_nHandlerStackDepth - 1]; + + // + // If a chunk handler was found in the handler map... + // + void *pData; + ChunkHandler_t pfnHandler = pHandler->GetHandler(szChunkName, &pData); + if (pfnHandler != NULL) + { + // Dispatch this chunk to the handler. + ChunkFileResult_t eResult = pfnHandler(this, pData); + if (eResult != ChunkFile_Ok) + { + return(eResult); + } + } + else + { + // + // No handler for this chunk. Skip to the matching close curly brace. + // + int nDepth = 1; + ChunkFileResult_t eResult; + + do + { + ChunkType_t eChunkType; + char szKey[MAX_KEYVALUE_LEN]; + char szValue[MAX_KEYVALUE_LEN]; + + while ((eResult = ReadNext(szKey, szValue, sizeof(szValue), eChunkType)) == ChunkFile_Ok) + { + if (eChunkType == ChunkType_Chunk) + { + nDepth++; + } + } + + if (eResult == ChunkFile_EndOfChunk) + { + eResult = ChunkFile_Ok; + nDepth--; + } + else if (eResult == ChunkFile_EOF) + { + return(ChunkFile_UnexpectedEOF); + } + + } while ((nDepth) && (eResult == ChunkFile_Ok)); + } + } + + return(ChunkFile_Ok); +} + + +//----------------------------------------------------------------------------- +// Purpose: Opens the chunk file for reading or writing. +// Input : pszFileName - Path of file to open. +// eMode - ChunkFile_Read or ChunkFile_Write. +// Output : Returns ChunkFile_Ok on success, ChunkFile_Fail on failure. +// UNDONE: boolean return value? +//----------------------------------------------------------------------------- +ChunkFileResult_t CChunkFile::Open(const char *pszFileName, ChunkFileOpenMode_t eMode) +{ + if (eMode == ChunkFile_Read) + { + // UNDONE: TokenReader encapsulates file - unify reading and writing to use the same file I/O. + // UNDONE: Support in-memory parsing. + if (m_TokenReader.Open(pszFileName)) + { + m_nCurrentDepth = 0; + } + else + { + return(ChunkFile_OpenFail); + } + } + else if (eMode == ChunkFile_Write) + { + m_hFile = fopen(pszFileName, "wb"); + + if (m_hFile == NULL) + { + return(ChunkFile_OpenFail); + } + + m_nCurrentDepth = 0; + } + + return(ChunkFile_Ok); +} + + +//----------------------------------------------------------------------------- +// Purpose: Removes the topmost set of chunk handlers. +//----------------------------------------------------------------------------- +void CChunkFile::PopHandlers(void) +{ + if (m_nHandlerStackDepth > 0) + { + m_nHandlerStackDepth--; + } +} + + +void CChunkFile::SetDefaultChunkHandler( DefaultChunkHandler_t pHandler, void *pData ) +{ + m_DefaultChunkHandler = pHandler; + m_pDefaultChunkHandlerData = pData;} + + +//----------------------------------------------------------------------------- +// Purpose: Adds a set of chunk handlers to the top of the handler stack. +// Input : pHandlerMap - Object containing the list of chunk handlers. +//----------------------------------------------------------------------------- +void CChunkFile::PushHandlers(CChunkHandlerMap *pHandlerMap) +{ + if (m_nHandlerStackDepth < MAX_INDENT_DEPTH) + { + m_HandlerStack[m_nHandlerStackDepth] = pHandlerMap; + m_nHandlerStackDepth++; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Reads the next term from the chunk file. The type of term read is +// returned in the eChunkType parameter. +// Input : szName - Name of key or chunk. +// szValue - If eChunkType is ChunkType_Key, contains the value of the key. +// nValueSize - Size of the buffer pointed to by szValue. +// eChunkType - ChunkType_Key or ChunkType_Chunk. +// Output : Returns ChunkFile_Ok on success, an error code if a parsing error occurs. +//----------------------------------------------------------------------------- +ChunkFileResult_t CChunkFile::ReadNext(char *szName, char *szValue, int nValueSize, ChunkType_t &eChunkType) +{ + // HACK: pass in buffer sizes? + trtoken_t eTokenType = m_TokenReader.NextToken(szName, MAX_KEYVALUE_LEN); + + if (eTokenType != TOKENEOF) + { + switch (eTokenType) + { + case IDENT: + case STRING: + { + char szNext[MAX_KEYVALUE_LEN]; + trtoken_t eNextTokenType; + + // + // Read the next token to determine what we have. + // + eNextTokenType = m_TokenReader.NextToken(szNext, sizeof(szNext)); + + switch (eNextTokenType) + { + case OPERATOR: + { + if (!stricmp(szNext, "{")) + { + // Beginning of new chunk. + m_nCurrentDepth++; + eChunkType = ChunkType_Chunk; + szValue[0] = '\0'; + return(ChunkFile_Ok); + } + else + { + // Unexpected symbol. + Q_strncpy(m_szErrorToken, szNext, sizeof( m_szErrorToken ) ); + return(ChunkFile_UnexpectedSymbol); + } + } + + case STRING: + case IDENT: + { + // Key value pair. + Q_strncpy(szValue, szNext, nValueSize ); + eChunkType = ChunkType_Key; + return(ChunkFile_Ok); + } + + case TOKENEOF: + { + // Unexpected end of file. + return(ChunkFile_UnexpectedEOF); + } + + case TOKENSTRINGTOOLONG: + { + // String too long or unterminated string. + return ChunkFile_StringTooLong; + } + } + } + + case OPERATOR: + { + if (!stricmp(szName, "}")) + { + // End of current chunk. + m_nCurrentDepth--; + return(ChunkFile_EndOfChunk); + } + else + { + // Unexpected symbol. + Q_strncpy(m_szErrorToken, szName, sizeof( m_szErrorToken ) ); + return(ChunkFile_UnexpectedSymbol); + } + } + + case TOKENSTRINGTOOLONG: + { + return ChunkFile_StringTooLong; + } + } + } + + if (m_nCurrentDepth != 0) + { + // End of file while within the scope of a chunk. + return(ChunkFile_UnexpectedEOF); + } + + return(ChunkFile_EOF); +} + + +//----------------------------------------------------------------------------- +// Purpose: Reads the current chunk and dispatches keys and sub-chunks to the +// appropriate handler callbacks. +// Input : pfnKeyHandler - Callback for any key values in this chunk. +// pData - Data to pass to the key value callback function. +// Output : Normally returns ChunkFile_Ok or ChunkFile_EOF. Otherwise, returns +// a ChunkFile_xxx error code. +//----------------------------------------------------------------------------- +ChunkFileResult_t CChunkFile::ReadChunk(KeyHandler_t pfnKeyHandler, void *pData) +{ + // + // Read the keys and sub-chunks. + // + ChunkFileResult_t eResult; + do + { + char szName[MAX_KEYVALUE_LEN]; + char szValue[MAX_KEYVALUE_LEN]; + ChunkType_t eChunkType; + + eResult = ReadNext(szName, szValue, sizeof(szValue), eChunkType); + + if (eResult == ChunkFile_Ok) + { + if (eChunkType == ChunkType_Chunk) + { + // + // Dispatch sub-chunks to the appropriate handler. + // + eResult = HandleChunk(szName); + } + else if ((eChunkType == ChunkType_Key) && (pfnKeyHandler != NULL)) + { + // + // Dispatch keys to the key value handler. + // + eResult = pfnKeyHandler(szName, szValue, pData); + } + } + } while (eResult == ChunkFile_Ok); + + // + // Cover up ChunkFile_EndOfChunk results because the caller doesn't want to see them. + // + if (eResult == ChunkFile_EndOfChunk) + { + eResult = ChunkFile_Ok; + } + + // + // Dispatch errors to the handler. + // + if ((eResult != ChunkFile_Ok) && (eResult != ChunkFile_EOF)) + { + //HandleError("chunkname", eResult); + } + + return(eResult); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pszValue - +// pbBool - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CChunkFile::ReadKeyValueBool(const char *pszValue, bool &bBool) +{ + int nValue = atoi(pszValue); + + if (nValue > 0) + { + bBool = true; + } + else + { + bBool = false; + } + + return(true); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pszValue - +// pfFloat - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CChunkFile::ReadKeyValueFloat(const char *pszValue, float &flFloat) +{ + flFloat = (float)atof(pszValue); + return(true); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pszValue - +// pnInt - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CChunkFile::ReadKeyValueInt(const char *pszValue, int &nInt) +{ + nInt = atoi(pszValue); + return(true); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pszKey - +// r - +// g - +// b - +// Output : +//----------------------------------------------------------------------------- +bool CChunkFile::ReadKeyValueColor(const char *pszValue, unsigned char &chRed, unsigned char &chGreen, unsigned char &chBlue) +{ + if (pszValue != NULL) + { + int r = 0; + int g = 0; + int b = 0; + + if (sscanf(pszValue, "%d %d %d", &r, &g, &b) == 3) + { + chRed = r; + chGreen = g; + chBlue = b; + + return(true); + } + } + + return(false); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pszValue - +// pfPoint - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CChunkFile::ReadKeyValuePoint(const char *pszValue, Vector &Point) +{ + if (pszValue != NULL) + { + return(sscanf(pszValue, "(%f %f %f)", &Point.x, &Point.y, &Point.z) == 3); + } + + return(false); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pszValue - +// pfVector - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CChunkFile::ReadKeyValueVector2(const char *pszValue, Vector2D &vec) +{ + if (pszValue != NULL) + { + return ( sscanf( pszValue, "[%f %f]", &vec.x, &vec.y) == 2 ); + } + + return(false); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pszValue - +// pfVector - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CChunkFile::ReadKeyValueVector3(const char *pszValue, Vector &vec) +{ + if (pszValue != NULL) + { + return(sscanf(pszValue, "[%f %f %f]", &vec.x, &vec.y, &vec.z) == 3); + } + + return(false); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pszValue - +// pfVector - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CChunkFile::ReadKeyValueVector4(const char *pszValue, Vector4D &vec) +{ + if( pszValue != NULL ) + { + return(sscanf(pszValue, "[%f %f %f %f]", &vec[0], &vec[1], &vec[2], &vec[3]) == 4); + } + + return false; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pszLine - +// Output : +//----------------------------------------------------------------------------- +ChunkFileResult_t CChunkFile::WriteKeyValue(const char *pszKey, const char *pszValue) +{ + if ((pszKey != NULL) && (pszValue != NULL)) + { + char szTemp[MAX_KEYVALUE_LEN]; + Q_snprintf(szTemp, sizeof( szTemp ), "\"%s\" \"%s\"", pszKey, pszValue); + return(WriteLine(szTemp)); + } + + return(ChunkFile_Ok); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pszKey - +// bValue - +// Output : +//----------------------------------------------------------------------------- +ChunkFileResult_t CChunkFile::WriteKeyValueBool(const char *pszKey, bool bValue) +{ + if (pszKey != NULL) + { + char szBuf[MAX_KEYVALUE_LEN]; + Q_snprintf(szBuf, sizeof( szBuf ), "\"%s\" \"%d\"", pszKey, (int)bValue); + return(WriteLine(szBuf)); + } + + return(ChunkFile_Ok); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pszKey - +// nValue - +// Output : +//----------------------------------------------------------------------------- +ChunkFileResult_t CChunkFile::WriteKeyValueInt(const char *pszKey, int nValue) +{ + if (pszKey != NULL) + { + char szBuf[MAX_KEYVALUE_LEN]; + Q_snprintf(szBuf, sizeof( szBuf ), "\"%s\" \"%d\"", pszKey, nValue); + return(WriteLine(szBuf)); + } + + return(ChunkFile_Ok); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pszKey - +// fValue - +// Output : +//----------------------------------------------------------------------------- +ChunkFileResult_t CChunkFile::WriteKeyValueFloat(const char *pszKey, float fValue) +{ + if (pszKey != NULL) + { + char szBuf[MAX_KEYVALUE_LEN]; + Q_snprintf(szBuf, sizeof( szBuf ), "\"%s\" \"%g\"", pszKey, (double)fValue); + return(WriteLine(szBuf)); + } + + return(ChunkFile_Ok); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pszKey - +// r - +// g - +// b - +// Output : +//----------------------------------------------------------------------------- +ChunkFileResult_t CChunkFile::WriteKeyValueColor(const char *pszKey, unsigned char r, unsigned char g, unsigned char b) +{ + if (pszKey != NULL) + { + char szBuf[MAX_KEYVALUE_LEN]; + Q_snprintf(szBuf, sizeof( szBuf ), "\"%s\" \"%d %d %d\"", pszKey, (int)r, (int)g, (int)b); + return(WriteLine(szBuf)); + } + + return(ChunkFile_Ok); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pszKey - +// fVector - +// Output : +//----------------------------------------------------------------------------- +ChunkFileResult_t CChunkFile::WriteKeyValuePoint(const char *pszKey, const Vector &Point) +{ + if (pszKey != NULL) + { + char szBuf[MAX_KEYVALUE_LEN]; + Q_snprintf(szBuf, sizeof( szBuf ), "\"%s\" \"(%g %g %g)\"", pszKey, (double)Point[0], (double)Point[1], (double)Point[2]); + return(WriteLine(szBuf)); + } + + return(ChunkFile_Ok); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +ChunkFileResult_t CChunkFile::WriteKeyValueVector2(const char *pszKey, const Vector2D &vec) +{ + if (pszKey != NULL) + { + char szBuf[MAX_KEYVALUE_LEN]; + Q_snprintf( szBuf, sizeof( szBuf ), "\"%s\" \"[%g %g]\"", pszKey, (double)vec.x, (double)vec.y ); + return(WriteLine(szBuf)); + } + + return(ChunkFile_Ok); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +ChunkFileResult_t CChunkFile::WriteKeyValueVector3(const char *pszKey, const Vector &vec) +{ + if (pszKey != NULL) + { + char szBuf[MAX_KEYVALUE_LEN]; + Q_snprintf(szBuf, sizeof( szBuf ), "\"%s\" \"[%g %g %g]\"", pszKey, (double)vec.x, (double)vec.y, (double)vec.z); + return(WriteLine(szBuf)); + } + + return(ChunkFile_Ok); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pszKey - +// fVector - +// Output : +//----------------------------------------------------------------------------- +ChunkFileResult_t CChunkFile::WriteKeyValueVector4(const char *pszKey, const Vector4D &vec) +{ + if (pszKey != NULL) + { + char szBuf[MAX_KEYVALUE_LEN]; + Q_snprintf(szBuf, sizeof( szBuf ), "\"%s\" \"[%g %g %g %g]\"", pszKey, (double)vec.x, (double)vec.y, (double)vec.z, (double)vec.w); + return( WriteLine( szBuf ) ); + } + + return( ChunkFile_Ok ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pszLine - +// Output : +//----------------------------------------------------------------------------- +ChunkFileResult_t CChunkFile::WriteLine(const char *pszLine) +{ + if (pszLine != NULL) + { + // + // Write the indentation string. + // + if (m_nCurrentDepth > 0) + { + int nWritten = fwrite(m_szIndent, 1, m_nCurrentDepth, m_hFile); + if (nWritten != m_nCurrentDepth) + { + return(ChunkFile_Fail); + } + } + + // + // Write the string. + // + int nLen = strlen(pszLine); + int nWritten = fwrite(pszLine, 1, nLen, m_hFile); + if (nWritten != nLen) + { + return(ChunkFile_Fail); + } + + // + // Write the linefeed. + // + if (fwrite("\r\n", 1, 2, m_hFile) != 2) + { + return(ChunkFile_Fail); + } + } + + return(ChunkFile_Ok); +} + -- cgit v1.2.3