Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

985 lines
25 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Implements an interface for reading and writing heirarchical
  4. // text files of key value pairs. The format of the file is as follows:
  5. //
  6. // chunkname0
  7. // {
  8. // "key0" "value0"
  9. // "key1" "value1"
  10. // ...
  11. // "keyN" "valueN"
  12. // chunkname1
  13. // {
  14. // "key0" "value0"
  15. // "key1" "value1"
  16. // ...
  17. // "keyN" "valueN"
  18. // }
  19. // }
  20. // ...
  21. // chunknameN
  22. // {
  23. // "key0" "value0"
  24. // "key1" "value1"
  25. // ...
  26. // "keyN" "valueN"
  27. // }
  28. //
  29. // The chunk names are not necessarily unique, nor are the key names, unless the
  30. // parsing application requires them to be.
  31. //
  32. // $NoKeywords: $
  33. //=============================================================================//
  34. #include <fcntl.h>
  35. #ifdef _WIN32
  36. #include <io.h>
  37. #endif
  38. #include <math.h>
  39. #include <sys/stat.h>
  40. #include <stdlib.h>
  41. #include <stdio.h>
  42. #include <string.h>
  43. #include "chunkfile.h"
  44. #include "mathlib/vector.h"
  45. #include "mathlib/vector4d.h"
  46. #include "tier1/strtools.h"
  47. // memdbgon must be the last include file in a .cpp file!!!
  48. #include "tier0/memdbgon.h"
  49. //-----------------------------------------------------------------------------
  50. // Purpose: Constructor.
  51. //-----------------------------------------------------------------------------
  52. CChunkHandlerMap::CChunkHandlerMap(void)
  53. {
  54. m_pHandlers = NULL;
  55. }
  56. //-----------------------------------------------------------------------------
  57. // Purpose: Destructor. Frees handler list.
  58. //-----------------------------------------------------------------------------
  59. CChunkHandlerMap::~CChunkHandlerMap(void)
  60. {
  61. ChunkHandlerInfoNode_t *pNode = m_pHandlers;
  62. while (pNode != NULL)
  63. {
  64. ChunkHandlerInfoNode_t *pPrev = pNode;
  65. pNode = pNode->pNext;
  66. delete pPrev;
  67. }
  68. }
  69. //-----------------------------------------------------------------------------
  70. // Purpose: Adds a chunk handler to the handler list.
  71. // Input : pszChunkName - Name of chunk to be handled.
  72. // pfnHandler - Address of handler callback function.
  73. // pData - Data to pass to the handler callback.
  74. //-----------------------------------------------------------------------------
  75. void CChunkHandlerMap::AddHandler(const char *pszChunkName, ChunkHandler_t pfnHandler, void *pData)
  76. {
  77. ChunkHandlerInfoNode_t *pNew = new ChunkHandlerInfoNode_t;
  78. Q_strncpy(pNew->Handler.szChunkName, pszChunkName, sizeof( pNew->Handler.szChunkName ));
  79. pNew->Handler.pfnHandler = pfnHandler;
  80. pNew->Handler.pData = pData;
  81. pNew->pNext = NULL;
  82. if (m_pHandlers == NULL)
  83. {
  84. m_pHandlers = pNew;
  85. }
  86. else
  87. {
  88. ChunkHandlerInfoNode_t *pNode = m_pHandlers;
  89. while (pNode->pNext != NULL)
  90. {
  91. pNode = pNode->pNext;
  92. }
  93. pNode->pNext = pNew;
  94. }
  95. }
  96. //-----------------------------------------------------------------------------
  97. // Purpose: Sets the callback for error handling within this chunk's scope.
  98. // Input : pfnHandler -
  99. // pData -
  100. //-----------------------------------------------------------------------------
  101. void CChunkHandlerMap::SetErrorHandler(ChunkErrorHandler_t pfnHandler, void *pData)
  102. {
  103. m_pfnErrorHandler = pfnHandler;
  104. m_pErrorData = pData;
  105. }
  106. //-----------------------------------------------------------------------------
  107. // Purpose:
  108. // Input : ppData -
  109. // Output : ChunkErrorHandler_t
  110. //-----------------------------------------------------------------------------
  111. ChunkErrorHandler_t CChunkHandlerMap::GetErrorHandler(void **ppData)
  112. {
  113. *ppData = m_pErrorData;
  114. return(m_pfnErrorHandler);
  115. }
  116. //-----------------------------------------------------------------------------
  117. // Purpose: Gets the handler for a given chunk name, if one has been set.
  118. // Input : pszChunkName - Name of chunk.
  119. // ppfnHandler - Receives the address of the callback function.
  120. // ppData - Receives the context data for the given chunk.
  121. // Output : Returns true if a handler was found, false if not.
  122. //-----------------------------------------------------------------------------
  123. ChunkHandler_t CChunkHandlerMap::GetHandler(const char *pszChunkName, void **ppData)
  124. {
  125. ChunkHandlerInfoNode_t *pNode = m_pHandlers;
  126. while (pNode != NULL)
  127. {
  128. if (!stricmp(pNode->Handler.szChunkName, pszChunkName))
  129. {
  130. *ppData = pNode->Handler.pData;
  131. return(pNode->Handler.pfnHandler);
  132. }
  133. pNode = pNode->pNext;
  134. }
  135. return(false);
  136. }
  137. //-----------------------------------------------------------------------------
  138. // Purpose: Constructor. Initializes data members.
  139. //-----------------------------------------------------------------------------
  140. CChunkFile::CChunkFile(void)
  141. {
  142. m_hFile = NULL;
  143. m_nCurrentDepth = 0;
  144. m_szIndent[0] = '\0';
  145. m_nHandlerStackDepth = 0;
  146. m_DefaultChunkHandler = 0;
  147. }
  148. //-----------------------------------------------------------------------------
  149. // Purpose: Destructor. Closes the file if it is currently open.
  150. //-----------------------------------------------------------------------------
  151. CChunkFile::~CChunkFile(void)
  152. {
  153. if (m_hFile != NULL)
  154. {
  155. fclose(m_hFile);
  156. }
  157. }
  158. //-----------------------------------------------------------------------------
  159. // Purpose:
  160. // Input : *pszChunkName -
  161. // Output : ChunkFileResult_t
  162. //-----------------------------------------------------------------------------
  163. ChunkFileResult_t CChunkFile::BeginChunk(const char *pszChunkName)
  164. {
  165. //
  166. // Write the chunk name and open curly.
  167. //
  168. char szBuf[MAX_KEYVALUE_LEN];
  169. Q_snprintf(szBuf, sizeof( szBuf ), "%s\r\n%s{", pszChunkName, m_szIndent);
  170. ChunkFileResult_t eResult = WriteLine(szBuf);
  171. //
  172. // Update the indentation depth.
  173. //
  174. if (eResult == ChunkFile_Ok)
  175. {
  176. m_nCurrentDepth++;
  177. BuildIndentString(m_szIndent, m_nCurrentDepth);
  178. }
  179. return(eResult);
  180. }
  181. //-----------------------------------------------------------------------------
  182. // Purpose:
  183. //-----------------------------------------------------------------------------
  184. void CChunkFile::BuildIndentString(char *pszDest, int nDepth)
  185. {
  186. if (nDepth >= 0)
  187. {
  188. for (int i = 0; i < nDepth; i++)
  189. {
  190. pszDest[i] = '\t';
  191. }
  192. pszDest[nDepth] = '\0';
  193. }
  194. }
  195. //-----------------------------------------------------------------------------
  196. // Purpose:
  197. // Output : ChunkFileResult_t
  198. //-----------------------------------------------------------------------------
  199. ChunkFileResult_t CChunkFile::Close(void)
  200. {
  201. if (m_hFile != NULL)
  202. {
  203. fclose(m_hFile);
  204. m_hFile = NULL;
  205. }
  206. return(ChunkFile_Ok);
  207. }
  208. //-----------------------------------------------------------------------------
  209. // Purpose:
  210. // Output : ChunkFileResult_t
  211. //-----------------------------------------------------------------------------
  212. ChunkFileResult_t CChunkFile::EndChunk(void)
  213. {
  214. if (m_nCurrentDepth > 0)
  215. {
  216. m_nCurrentDepth--;
  217. BuildIndentString(m_szIndent, m_nCurrentDepth);
  218. }
  219. WriteLine("}");
  220. return(ChunkFile_Ok);
  221. }
  222. //-----------------------------------------------------------------------------
  223. // Purpose: Returns a string explaining the last error that occurred.
  224. //-----------------------------------------------------------------------------
  225. const char *CChunkFile::GetErrorText(ChunkFileResult_t eResult)
  226. {
  227. static char szError[MAX_KEYVALUE_LEN];
  228. switch (eResult)
  229. {
  230. case ChunkFile_UnexpectedEOF:
  231. {
  232. Q_strncpy(szError, "unexpected end of file", sizeof( szError ) );
  233. break;
  234. }
  235. case ChunkFile_UnexpectedSymbol:
  236. {
  237. Q_snprintf(szError, sizeof( szError ), "unexpected symbol '%s'", m_szErrorToken);
  238. break;
  239. }
  240. case ChunkFile_OpenFail:
  241. {
  242. Q_snprintf(szError, sizeof( szError ), "%s", strerror(errno)) ;
  243. break;
  244. }
  245. case ChunkFile_StringTooLong:
  246. {
  247. Q_strncpy(szError, "unterminated string or string too long", sizeof( szError ) );
  248. break;
  249. }
  250. default:
  251. {
  252. Q_snprintf(szError, sizeof( szError ), "error %d", eResult);
  253. }
  254. }
  255. return(m_TokenReader.Error(szError));
  256. }
  257. //-----------------------------------------------------------------------------
  258. // Purpose:
  259. // Input : eError -
  260. //-----------------------------------------------------------------------------
  261. void CChunkFile::HandleError(const char *szChunkName, ChunkFileResult_t eError)
  262. {
  263. // UNDONE: dispatch errors to the error handler.
  264. // - keep track of current chunkname for reporting errors
  265. // - use the last non-NULL handler that was pushed onto the stack?
  266. // - need a return code to determine whether to abort parsing?
  267. }
  268. //-----------------------------------------------------------------------------
  269. // Purpose:
  270. // Output : ChunkFileResult_t
  271. //-----------------------------------------------------------------------------
  272. ChunkFileResult_t CChunkFile::HandleChunk(const char *szChunkName)
  273. {
  274. // See if the default handler wants it?
  275. if( m_DefaultChunkHandler )
  276. {
  277. ChunkFileResult_t testResult = m_DefaultChunkHandler( this, m_pDefaultChunkHandlerData, szChunkName );
  278. if( testResult == ChunkFile_Ok )
  279. {
  280. return ChunkFile_Ok;
  281. }
  282. }
  283. //
  284. // If there is an active handler map...
  285. //
  286. if (m_nHandlerStackDepth > 0)
  287. {
  288. CChunkHandlerMap *pHandler = m_HandlerStack[m_nHandlerStackDepth - 1];
  289. //
  290. // If a chunk handler was found in the handler map...
  291. //
  292. void *pData;
  293. ChunkHandler_t pfnHandler = pHandler->GetHandler(szChunkName, &pData);
  294. if (pfnHandler != NULL)
  295. {
  296. // Dispatch this chunk to the handler.
  297. ChunkFileResult_t eResult = pfnHandler(this, pData);
  298. if (eResult != ChunkFile_Ok)
  299. {
  300. return(eResult);
  301. }
  302. }
  303. else
  304. {
  305. //
  306. // No handler for this chunk. Skip to the matching close curly brace.
  307. //
  308. int nDepth = 1;
  309. ChunkFileResult_t eResult;
  310. do
  311. {
  312. ChunkType_t eChunkType;
  313. char szKey[MAX_KEYVALUE_LEN];
  314. char szValue[MAX_KEYVALUE_LEN];
  315. while ((eResult = ReadNext(szKey, szValue, sizeof(szValue), eChunkType)) == ChunkFile_Ok)
  316. {
  317. if (eChunkType == ChunkType_Chunk)
  318. {
  319. nDepth++;
  320. }
  321. }
  322. if (eResult == ChunkFile_EndOfChunk)
  323. {
  324. eResult = ChunkFile_Ok;
  325. nDepth--;
  326. }
  327. else if (eResult == ChunkFile_EOF)
  328. {
  329. return(ChunkFile_UnexpectedEOF);
  330. }
  331. } while ((nDepth) && (eResult == ChunkFile_Ok));
  332. }
  333. }
  334. return(ChunkFile_Ok);
  335. }
  336. //-----------------------------------------------------------------------------
  337. // Purpose: Opens the chunk file for reading or writing.
  338. // Input : pszFileName - Path of file to open.
  339. // eMode - ChunkFile_Read or ChunkFile_Write.
  340. // Output : Returns ChunkFile_Ok on success, ChunkFile_Fail on failure.
  341. // UNDONE: boolean return value?
  342. //-----------------------------------------------------------------------------
  343. ChunkFileResult_t CChunkFile::Open(const char *pszFileName, ChunkFileOpenMode_t eMode)
  344. {
  345. if (eMode == ChunkFile_Read)
  346. {
  347. // UNDONE: TokenReader encapsulates file - unify reading and writing to use the same file I/O.
  348. // UNDONE: Support in-memory parsing.
  349. if (m_TokenReader.Open(pszFileName))
  350. {
  351. m_nCurrentDepth = 0;
  352. }
  353. else
  354. {
  355. return(ChunkFile_OpenFail);
  356. }
  357. }
  358. else if (eMode == ChunkFile_Write)
  359. {
  360. m_hFile = fopen(pszFileName, "wb");
  361. if (m_hFile == NULL)
  362. {
  363. return(ChunkFile_OpenFail);
  364. }
  365. m_nCurrentDepth = 0;
  366. }
  367. return(ChunkFile_Ok);
  368. }
  369. //-----------------------------------------------------------------------------
  370. // Purpose: Removes the topmost set of chunk handlers.
  371. //-----------------------------------------------------------------------------
  372. void CChunkFile::PopHandlers(void)
  373. {
  374. if (m_nHandlerStackDepth > 0)
  375. {
  376. m_nHandlerStackDepth--;
  377. }
  378. }
  379. void CChunkFile::SetDefaultChunkHandler( DefaultChunkHandler_t pHandler, void *pData )
  380. {
  381. m_DefaultChunkHandler = pHandler;
  382. m_pDefaultChunkHandlerData = pData;}
  383. //-----------------------------------------------------------------------------
  384. // Purpose: Adds a set of chunk handlers to the top of the handler stack.
  385. // Input : pHandlerMap - Object containing the list of chunk handlers.
  386. //-----------------------------------------------------------------------------
  387. void CChunkFile::PushHandlers(CChunkHandlerMap *pHandlerMap)
  388. {
  389. if (m_nHandlerStackDepth < MAX_INDENT_DEPTH)
  390. {
  391. m_HandlerStack[m_nHandlerStackDepth] = pHandlerMap;
  392. m_nHandlerStackDepth++;
  393. }
  394. }
  395. //-----------------------------------------------------------------------------
  396. // Purpose: Reads the next term from the chunk file. The type of term read is
  397. // returned in the eChunkType parameter.
  398. // Input : szName - Name of key or chunk.
  399. // szValue - If eChunkType is ChunkType_Key, contains the value of the key.
  400. // nValueSize - Size of the buffer pointed to by szValue.
  401. // eChunkType - ChunkType_Key or ChunkType_Chunk.
  402. // Output : Returns ChunkFile_Ok on success, an error code if a parsing error occurs.
  403. //-----------------------------------------------------------------------------
  404. ChunkFileResult_t CChunkFile::ReadNext(char *szName, char *szValue, int nValueSize, ChunkType_t &eChunkType)
  405. {
  406. // HACK: pass in buffer sizes?
  407. trtoken_t eTokenType = m_TokenReader.NextToken(szName, MAX_KEYVALUE_LEN);
  408. if (eTokenType != TOKENEOF)
  409. {
  410. switch (eTokenType)
  411. {
  412. case IDENT:
  413. case STRING:
  414. {
  415. char szNext[MAX_KEYVALUE_LEN];
  416. trtoken_t eNextTokenType;
  417. //
  418. // Read the next token to determine what we have.
  419. //
  420. eNextTokenType = m_TokenReader.NextToken(szNext, sizeof(szNext));
  421. switch (eNextTokenType)
  422. {
  423. case OPERATOR:
  424. {
  425. if (!stricmp(szNext, "{"))
  426. {
  427. // Beginning of new chunk.
  428. m_nCurrentDepth++;
  429. eChunkType = ChunkType_Chunk;
  430. szValue[0] = '\0';
  431. return(ChunkFile_Ok);
  432. }
  433. else
  434. {
  435. // Unexpected symbol.
  436. Q_strncpy(m_szErrorToken, szNext, sizeof( m_szErrorToken ) );
  437. return(ChunkFile_UnexpectedSymbol);
  438. }
  439. }
  440. case STRING:
  441. case IDENT:
  442. {
  443. // Key value pair.
  444. Q_strncpy(szValue, szNext, nValueSize );
  445. eChunkType = ChunkType_Key;
  446. return(ChunkFile_Ok);
  447. }
  448. case TOKENEOF:
  449. {
  450. // Unexpected end of file.
  451. return(ChunkFile_UnexpectedEOF);
  452. }
  453. case TOKENSTRINGTOOLONG:
  454. {
  455. // String too long or unterminated string.
  456. return ChunkFile_StringTooLong;
  457. }
  458. }
  459. }
  460. case OPERATOR:
  461. {
  462. if (!stricmp(szName, "}"))
  463. {
  464. // End of current chunk.
  465. m_nCurrentDepth--;
  466. return(ChunkFile_EndOfChunk);
  467. }
  468. else
  469. {
  470. // Unexpected symbol.
  471. Q_strncpy(m_szErrorToken, szName, sizeof( m_szErrorToken ) );
  472. return(ChunkFile_UnexpectedSymbol);
  473. }
  474. }
  475. case TOKENSTRINGTOOLONG:
  476. {
  477. return ChunkFile_StringTooLong;
  478. }
  479. }
  480. }
  481. if (m_nCurrentDepth != 0)
  482. {
  483. // End of file while within the scope of a chunk.
  484. return(ChunkFile_UnexpectedEOF);
  485. }
  486. return(ChunkFile_EOF);
  487. }
  488. //-----------------------------------------------------------------------------
  489. // Purpose: Reads the current chunk and dispatches keys and sub-chunks to the
  490. // appropriate handler callbacks.
  491. // Input : pfnKeyHandler - Callback for any key values in this chunk.
  492. // pData - Data to pass to the key value callback function.
  493. // Output : Normally returns ChunkFile_Ok or ChunkFile_EOF. Otherwise, returns
  494. // a ChunkFile_xxx error code.
  495. //-----------------------------------------------------------------------------
  496. ChunkFileResult_t CChunkFile::ReadChunk(KeyHandler_t pfnKeyHandler, void *pData)
  497. {
  498. //
  499. // Read the keys and sub-chunks.
  500. //
  501. ChunkFileResult_t eResult;
  502. do
  503. {
  504. char szName[MAX_KEYVALUE_LEN];
  505. char szValue[MAX_KEYVALUE_LEN];
  506. ChunkType_t eChunkType;
  507. eResult = ReadNext(szName, szValue, sizeof(szValue), eChunkType);
  508. if (eResult == ChunkFile_Ok)
  509. {
  510. if (eChunkType == ChunkType_Chunk)
  511. {
  512. //
  513. // Dispatch sub-chunks to the appropriate handler.
  514. //
  515. eResult = HandleChunk(szName);
  516. }
  517. else if ((eChunkType == ChunkType_Key) && (pfnKeyHandler != NULL))
  518. {
  519. //
  520. // Dispatch keys to the key value handler.
  521. //
  522. eResult = pfnKeyHandler(szName, szValue, pData);
  523. }
  524. }
  525. } while (eResult == ChunkFile_Ok);
  526. //
  527. // Cover up ChunkFile_EndOfChunk results because the caller doesn't want to see them.
  528. //
  529. if (eResult == ChunkFile_EndOfChunk)
  530. {
  531. eResult = ChunkFile_Ok;
  532. }
  533. //
  534. // Dispatch errors to the handler.
  535. //
  536. if ((eResult != ChunkFile_Ok) && (eResult != ChunkFile_EOF))
  537. {
  538. //HandleError("chunkname", eResult);
  539. }
  540. return(eResult);
  541. }
  542. //-----------------------------------------------------------------------------
  543. // Purpose:
  544. // Input : pszValue -
  545. // pbBool -
  546. // Output : Returns true on success, false on failure.
  547. //-----------------------------------------------------------------------------
  548. bool CChunkFile::ReadKeyValueBool(const char *pszValue, bool &bBool)
  549. {
  550. int nValue = atoi(pszValue);
  551. if (nValue > 0)
  552. {
  553. bBool = true;
  554. }
  555. else
  556. {
  557. bBool = false;
  558. }
  559. return(true);
  560. }
  561. //-----------------------------------------------------------------------------
  562. // Purpose:
  563. // Input : pszValue -
  564. // pfFloat -
  565. // Output : Returns true on success, false on failure.
  566. //-----------------------------------------------------------------------------
  567. bool CChunkFile::ReadKeyValueFloat(const char *pszValue, float &flFloat)
  568. {
  569. flFloat = (float)atof(pszValue);
  570. return(true);
  571. }
  572. //-----------------------------------------------------------------------------
  573. // Purpose:
  574. // Input : pszValue -
  575. // pnInt -
  576. // Output : Returns true on success, false on failure.
  577. //-----------------------------------------------------------------------------
  578. bool CChunkFile::ReadKeyValueInt(const char *pszValue, int &nInt)
  579. {
  580. nInt = atoi(pszValue);
  581. return(true);
  582. }
  583. //-----------------------------------------------------------------------------
  584. // Purpose:
  585. // Input : pszKey -
  586. // r -
  587. // g -
  588. // b -
  589. // Output :
  590. //-----------------------------------------------------------------------------
  591. bool CChunkFile::ReadKeyValueColor(const char *pszValue, unsigned char &chRed, unsigned char &chGreen, unsigned char &chBlue)
  592. {
  593. if (pszValue != NULL)
  594. {
  595. int r = 0;
  596. int g = 0;
  597. int b = 0;
  598. if (sscanf(pszValue, "%d %d %d", &r, &g, &b) == 3)
  599. {
  600. chRed = r;
  601. chGreen = g;
  602. chBlue = b;
  603. return(true);
  604. }
  605. }
  606. return(false);
  607. }
  608. //-----------------------------------------------------------------------------
  609. // Purpose:
  610. // Input : pszValue -
  611. // pfPoint -
  612. // Output : Returns true on success, false on failure.
  613. //-----------------------------------------------------------------------------
  614. bool CChunkFile::ReadKeyValuePoint(const char *pszValue, Vector &Point)
  615. {
  616. if (pszValue != NULL)
  617. {
  618. return(sscanf(pszValue, "(%f %f %f)", &Point.x, &Point.y, &Point.z) == 3);
  619. }
  620. return(false);
  621. }
  622. //-----------------------------------------------------------------------------
  623. // Purpose:
  624. // Input : pszValue -
  625. // pfVector -
  626. // Output : Returns true on success, false on failure.
  627. //-----------------------------------------------------------------------------
  628. bool CChunkFile::ReadKeyValueVector2(const char *pszValue, Vector2D &vec)
  629. {
  630. if (pszValue != NULL)
  631. {
  632. return ( sscanf( pszValue, "[%f %f]", &vec.x, &vec.y) == 2 );
  633. }
  634. return(false);
  635. }
  636. //-----------------------------------------------------------------------------
  637. // Purpose:
  638. // Input : pszValue -
  639. // pfVector -
  640. // Output : Returns true on success, false on failure.
  641. //-----------------------------------------------------------------------------
  642. bool CChunkFile::ReadKeyValueVector3(const char *pszValue, Vector &vec)
  643. {
  644. if (pszValue != NULL)
  645. {
  646. return(sscanf(pszValue, "[%f %f %f]", &vec.x, &vec.y, &vec.z) == 3);
  647. }
  648. return(false);
  649. }
  650. //-----------------------------------------------------------------------------
  651. // Purpose:
  652. // Input : pszValue -
  653. // pfVector -
  654. // Output : Returns true on success, false on failure.
  655. //-----------------------------------------------------------------------------
  656. bool CChunkFile::ReadKeyValueVector4(const char *pszValue, Vector4D &vec)
  657. {
  658. if( pszValue != NULL )
  659. {
  660. return(sscanf(pszValue, "[%f %f %f %f]", &vec[0], &vec[1], &vec[2], &vec[3]) == 4);
  661. }
  662. return false;
  663. }
  664. //-----------------------------------------------------------------------------
  665. // Purpose:
  666. // Input : pszLine -
  667. // Output :
  668. //-----------------------------------------------------------------------------
  669. ChunkFileResult_t CChunkFile::WriteKeyValue(const char *pszKey, const char *pszValue)
  670. {
  671. if ((pszKey != NULL) && (pszValue != NULL))
  672. {
  673. char szTemp[MAX_KEYVALUE_LEN];
  674. Q_snprintf(szTemp, sizeof( szTemp ), "\"%s\" \"%s\"", pszKey, pszValue);
  675. return(WriteLine(szTemp));
  676. }
  677. return(ChunkFile_Ok);
  678. }
  679. //-----------------------------------------------------------------------------
  680. // Purpose:
  681. // Input : pszKey -
  682. // bValue -
  683. // Output :
  684. //-----------------------------------------------------------------------------
  685. ChunkFileResult_t CChunkFile::WriteKeyValueBool(const char *pszKey, bool bValue)
  686. {
  687. if (pszKey != NULL)
  688. {
  689. char szBuf[MAX_KEYVALUE_LEN];
  690. Q_snprintf(szBuf, sizeof( szBuf ), "\"%s\" \"%d\"", pszKey, (int)bValue);
  691. return(WriteLine(szBuf));
  692. }
  693. return(ChunkFile_Ok);
  694. }
  695. //-----------------------------------------------------------------------------
  696. // Purpose:
  697. // Input : pszKey -
  698. // nValue -
  699. // Output :
  700. //-----------------------------------------------------------------------------
  701. ChunkFileResult_t CChunkFile::WriteKeyValueInt(const char *pszKey, int nValue)
  702. {
  703. if (pszKey != NULL)
  704. {
  705. char szBuf[MAX_KEYVALUE_LEN];
  706. Q_snprintf(szBuf, sizeof( szBuf ), "\"%s\" \"%d\"", pszKey, nValue);
  707. return(WriteLine(szBuf));
  708. }
  709. return(ChunkFile_Ok);
  710. }
  711. //-----------------------------------------------------------------------------
  712. // Purpose:
  713. // Input : pszKey -
  714. // fValue -
  715. // Output :
  716. //-----------------------------------------------------------------------------
  717. ChunkFileResult_t CChunkFile::WriteKeyValueFloat(const char *pszKey, float fValue)
  718. {
  719. if (pszKey != NULL)
  720. {
  721. char szBuf[MAX_KEYVALUE_LEN];
  722. Q_snprintf(szBuf, sizeof( szBuf ), "\"%s\" \"%g\"", pszKey, (double)fValue);
  723. return(WriteLine(szBuf));
  724. }
  725. return(ChunkFile_Ok);
  726. }
  727. //-----------------------------------------------------------------------------
  728. // Purpose:
  729. // Input : pszKey -
  730. // r -
  731. // g -
  732. // b -
  733. // Output :
  734. //-----------------------------------------------------------------------------
  735. ChunkFileResult_t CChunkFile::WriteKeyValueColor(const char *pszKey, unsigned char r, unsigned char g, unsigned char b)
  736. {
  737. if (pszKey != NULL)
  738. {
  739. char szBuf[MAX_KEYVALUE_LEN];
  740. Q_snprintf(szBuf, sizeof( szBuf ), "\"%s\" \"%d %d %d\"", pszKey, (int)r, (int)g, (int)b);
  741. return(WriteLine(szBuf));
  742. }
  743. return(ChunkFile_Ok);
  744. }
  745. //-----------------------------------------------------------------------------
  746. // Purpose:
  747. // Input : pszKey -
  748. // fVector -
  749. // Output :
  750. //-----------------------------------------------------------------------------
  751. ChunkFileResult_t CChunkFile::WriteKeyValuePoint(const char *pszKey, const Vector &Point)
  752. {
  753. if (pszKey != NULL)
  754. {
  755. char szBuf[MAX_KEYVALUE_LEN];
  756. Q_snprintf(szBuf, sizeof( szBuf ), "\"%s\" \"(%g %g %g)\"", pszKey, (double)Point[0], (double)Point[1], (double)Point[2]);
  757. return(WriteLine(szBuf));
  758. }
  759. return(ChunkFile_Ok);
  760. }
  761. //-----------------------------------------------------------------------------
  762. // Purpose:
  763. //-----------------------------------------------------------------------------
  764. ChunkFileResult_t CChunkFile::WriteKeyValueVector2(const char *pszKey, const Vector2D &vec)
  765. {
  766. if (pszKey != NULL)
  767. {
  768. char szBuf[MAX_KEYVALUE_LEN];
  769. Q_snprintf( szBuf, sizeof( szBuf ), "\"%s\" \"[%g %g]\"", pszKey, (double)vec.x, (double)vec.y );
  770. return(WriteLine(szBuf));
  771. }
  772. return(ChunkFile_Ok);
  773. }
  774. //-----------------------------------------------------------------------------
  775. // Purpose:
  776. //-----------------------------------------------------------------------------
  777. ChunkFileResult_t CChunkFile::WriteKeyValueVector3(const char *pszKey, const Vector &vec)
  778. {
  779. if (pszKey != NULL)
  780. {
  781. char szBuf[MAX_KEYVALUE_LEN];
  782. Q_snprintf(szBuf, sizeof( szBuf ), "\"%s\" \"[%g %g %g]\"", pszKey, (double)vec.x, (double)vec.y, (double)vec.z);
  783. return(WriteLine(szBuf));
  784. }
  785. return(ChunkFile_Ok);
  786. }
  787. //-----------------------------------------------------------------------------
  788. // Purpose:
  789. // Input : pszKey -
  790. // fVector -
  791. // Output :
  792. //-----------------------------------------------------------------------------
  793. ChunkFileResult_t CChunkFile::WriteKeyValueVector4(const char *pszKey, const Vector4D &vec)
  794. {
  795. if (pszKey != NULL)
  796. {
  797. char szBuf[MAX_KEYVALUE_LEN];
  798. Q_snprintf(szBuf, sizeof( szBuf ), "\"%s\" \"[%g %g %g %g]\"", pszKey, (double)vec.x, (double)vec.y, (double)vec.z, (double)vec.w);
  799. return( WriteLine( szBuf ) );
  800. }
  801. return( ChunkFile_Ok );
  802. }
  803. //-----------------------------------------------------------------------------
  804. // Purpose:
  805. // Input : *pszLine -
  806. // Output :
  807. //-----------------------------------------------------------------------------
  808. ChunkFileResult_t CChunkFile::WriteLine(const char *pszLine)
  809. {
  810. if (pszLine != NULL)
  811. {
  812. //
  813. // Write the indentation string.
  814. //
  815. if (m_nCurrentDepth > 0)
  816. {
  817. int nWritten = fwrite(m_szIndent, 1, m_nCurrentDepth, m_hFile);
  818. if (nWritten != m_nCurrentDepth)
  819. {
  820. return(ChunkFile_Fail);
  821. }
  822. }
  823. //
  824. // Write the string.
  825. //
  826. int nLen = strlen(pszLine);
  827. int nWritten = fwrite(pszLine, 1, nLen, m_hFile);
  828. if (nWritten != nLen)
  829. {
  830. return(ChunkFile_Fail);
  831. }
  832. //
  833. // Write the linefeed.
  834. //
  835. if (fwrite("\r\n", 1, 2, m_hFile) != 2)
  836. {
  837. return(ChunkFile_Fail);
  838. }
  839. }
  840. return(ChunkFile_Ok);
  841. }