mirror of
https://github.com/alliedmodders/hl2sdk.git
synced 2025-09-19 20:16:10 +08:00
First version of the SOurce SDK 2013
This commit is contained in:
985
public/chunkfile.cpp
Normal file
985
public/chunkfile.cpp
Normal file
@ -0,0 +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 <fcntl.h>
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#endif
|
||||
#include <math.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user