Counter Strike : Global Offensive Source Code
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.

1914 lines
45 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // $Header: $
  4. // $NoKeywords: $
  5. //
  6. // Serialization buffer
  7. //===========================================================================//
  8. #pragma warning (disable : 4514)
  9. #include "utlbuffer.h"
  10. #include <stdio.h>
  11. #include <stdarg.h>
  12. #include <ctype.h>
  13. #include <stdlib.h>
  14. #include <limits.h>
  15. #include "tier1/strtools.h"
  16. #include "tier1/characterset.h"
  17. // memdbgon must be the last include file in a .cpp file!!!
  18. #include "tier0/memdbgon.h"
  19. //-----------------------------------------------------------------------------
  20. // Character conversions for C strings
  21. //-----------------------------------------------------------------------------
  22. class CUtlCStringConversion : public CUtlCharConversion
  23. {
  24. public:
  25. CUtlCStringConversion( char nEscapeChar, const char *pDelimiter, int nCount, ConversionArray_t *pArray );
  26. // Finds a conversion for the passed-in string, returns length
  27. virtual char FindConversion( const char *pString, int *pLength );
  28. private:
  29. char m_pConversion[256];
  30. };
  31. //-----------------------------------------------------------------------------
  32. // Character conversions for no-escape sequence strings
  33. //-----------------------------------------------------------------------------
  34. class CUtlNoEscConversion : public CUtlCharConversion
  35. {
  36. public:
  37. CUtlNoEscConversion( char nEscapeChar, const char *pDelimiter, int nCount, ConversionArray_t *pArray ) :
  38. CUtlCharConversion( nEscapeChar, pDelimiter, nCount, pArray ) {}
  39. // Finds a conversion for the passed-in string, returns length
  40. virtual char FindConversion( const char *pString, int *pLength ) { *pLength = 0; return 0; }
  41. };
  42. //-----------------------------------------------------------------------------
  43. // List of character conversions
  44. //-----------------------------------------------------------------------------
  45. BEGIN_CUSTOM_CHAR_CONVERSION( CUtlCStringConversion, s_StringCharConversion, "\"", '\\' )
  46. { '\n', "n" },
  47. { '\t', "t" },
  48. { '\v', "v" },
  49. { '\b', "b" },
  50. { '\r', "r" },
  51. { '\f', "f" },
  52. { '\a', "a" },
  53. { '\\', "\\" },
  54. { '\?', "\?" },
  55. { '\'', "\'" },
  56. { '\"', "\"" },
  57. END_CUSTOM_CHAR_CONVERSION( CUtlCStringConversion, s_StringCharConversion, "\"", '\\' )
  58. CUtlCharConversion *GetCStringCharConversion()
  59. {
  60. return &s_StringCharConversion;
  61. }
  62. BEGIN_CUSTOM_CHAR_CONVERSION( CUtlNoEscConversion, s_NoEscConversion, "\"", 0x7F )
  63. { 0x7F, "" },
  64. END_CUSTOM_CHAR_CONVERSION( CUtlNoEscConversion, s_NoEscConversion, "\"", 0x7F )
  65. CUtlCharConversion *GetNoEscCharConversion()
  66. {
  67. return &s_NoEscConversion;
  68. }
  69. //-----------------------------------------------------------------------------
  70. // Constructor
  71. //-----------------------------------------------------------------------------
  72. CUtlCStringConversion::CUtlCStringConversion( char nEscapeChar, const char *pDelimiter, int nCount, ConversionArray_t *pArray ) :
  73. CUtlCharConversion( nEscapeChar, pDelimiter, nCount, pArray )
  74. {
  75. memset( m_pConversion, 0x0, sizeof(m_pConversion) );
  76. for ( int i = 0; i < nCount; ++i )
  77. {
  78. m_pConversion[ (unsigned char)(pArray[i].m_pReplacementString[0]) ] = pArray[i].m_nActualChar;
  79. }
  80. }
  81. // Finds a conversion for the passed-in string, returns length
  82. char CUtlCStringConversion::FindConversion( const char *pString, int *pLength )
  83. {
  84. char c = m_pConversion[ (unsigned char)( pString[0] ) ];
  85. *pLength = (c != '\0') ? 1 : 0;
  86. return c;
  87. }
  88. //-----------------------------------------------------------------------------
  89. // Constructor
  90. //-----------------------------------------------------------------------------
  91. CUtlCharConversion::CUtlCharConversion( char nEscapeChar, const char *pDelimiter, int nCount, ConversionArray_t *pArray )
  92. {
  93. m_nEscapeChar = nEscapeChar;
  94. m_pDelimiter = pDelimiter;
  95. m_nCount = nCount;
  96. m_nDelimiterLength = V_strlen( pDelimiter );
  97. m_nMaxConversionLength = 0;
  98. memset( m_pReplacements, 0, sizeof(m_pReplacements) );
  99. for ( int i = 0; i < nCount; ++i )
  100. {
  101. m_pList[i] = pArray[i].m_nActualChar;
  102. ConversionInfo_t &info = m_pReplacements[ (unsigned char)( m_pList[i] ) ];
  103. Assert( info.m_pReplacementString == 0 );
  104. info.m_pReplacementString = pArray[i].m_pReplacementString;
  105. info.m_nLength = V_strlen( info.m_pReplacementString );
  106. if ( info.m_nLength > m_nMaxConversionLength )
  107. {
  108. m_nMaxConversionLength = info.m_nLength;
  109. }
  110. }
  111. }
  112. //-----------------------------------------------------------------------------
  113. // Escape character + delimiter
  114. //-----------------------------------------------------------------------------
  115. char CUtlCharConversion::GetEscapeChar() const
  116. {
  117. return m_nEscapeChar;
  118. }
  119. const char *CUtlCharConversion::GetDelimiter() const
  120. {
  121. return m_pDelimiter;
  122. }
  123. int CUtlCharConversion::GetDelimiterLength() const
  124. {
  125. return m_nDelimiterLength;
  126. }
  127. //-----------------------------------------------------------------------------
  128. // Constructor
  129. //-----------------------------------------------------------------------------
  130. const char *CUtlCharConversion::GetConversionString( char c ) const
  131. {
  132. return m_pReplacements[ (unsigned char)c ].m_pReplacementString;
  133. }
  134. int CUtlCharConversion::GetConversionLength( char c ) const
  135. {
  136. return m_pReplacements[ (unsigned char)c ].m_nLength;
  137. }
  138. int CUtlCharConversion::MaxConversionLength() const
  139. {
  140. return m_nMaxConversionLength;
  141. }
  142. //-----------------------------------------------------------------------------
  143. // Finds a conversion for the passed-in string, returns length
  144. //-----------------------------------------------------------------------------
  145. char CUtlCharConversion::FindConversion( const char *pString, int *pLength )
  146. {
  147. for ( int i = 0; i < m_nCount; ++i )
  148. {
  149. if ( !V_strcmp( pString, m_pReplacements[ (unsigned char)( m_pList[i] ) ].m_pReplacementString ) )
  150. {
  151. *pLength = m_pReplacements[ (unsigned char)( m_pList[i] ) ].m_nLength;
  152. return m_pList[i];
  153. }
  154. }
  155. *pLength = 0;
  156. return '\0';
  157. }
  158. //-----------------------------------------------------------------------------
  159. // constructors
  160. //-----------------------------------------------------------------------------
  161. CUtlBuffer::CUtlBuffer( int growSize, int initSize, int nFlags ) :
  162. m_Error(0)
  163. {
  164. MEM_ALLOC_CREDIT();
  165. m_Memory.Init( growSize, initSize );
  166. m_Get = 0;
  167. m_Put = 0;
  168. m_nTab = 0;
  169. m_nOffset = 0;
  170. m_Flags = nFlags;
  171. if ( (initSize != 0) && !IsReadOnly() )
  172. {
  173. m_nMaxPut = -1;
  174. AddNullTermination( m_Put );
  175. }
  176. else
  177. {
  178. m_nMaxPut = 0;
  179. }
  180. SetOverflowFuncs( &CUtlBuffer::GetOverflow, &CUtlBuffer::PutOverflow );
  181. }
  182. CUtlBuffer::CUtlBuffer( const void *pBuffer, int nSize, int nFlags ) :
  183. m_Memory( (unsigned char*)pBuffer, nSize ), m_Error(0)
  184. {
  185. Assert( nSize != 0 );
  186. m_Get = 0;
  187. m_Put = 0;
  188. m_nTab = 0;
  189. m_nOffset = 0;
  190. m_Flags = nFlags;
  191. if ( IsReadOnly() )
  192. {
  193. m_nMaxPut = m_Put = nSize;
  194. }
  195. else
  196. {
  197. m_nMaxPut = -1;
  198. AddNullTermination( m_Put );
  199. }
  200. SetOverflowFuncs( &CUtlBuffer::GetOverflow, &CUtlBuffer::PutOverflow );
  201. }
  202. CUtlBuffer::CUtlBuffer( const CUtlBuffer& copyFrom )
  203. : m_Get( copyFrom.m_Get )
  204. , m_Put( copyFrom.m_Put )
  205. , m_Error( copyFrom.m_Error )
  206. , m_Flags( copyFrom.m_Flags )
  207. , m_Reserved( copyFrom.m_Reserved )
  208. #if defined( _GAMECONSOLE )
  209. , pad( copyFrom.pad )
  210. #endif
  211. , m_nTab( copyFrom.m_nTab )
  212. , m_nMaxPut( copyFrom.m_nMaxPut )
  213. , m_nOffset( copyFrom.m_nOffset )
  214. , m_GetOverflowFunc( copyFrom.m_GetOverflowFunc )
  215. , m_PutOverflowFunc( copyFrom.m_PutOverflowFunc )
  216. , m_Byteswap( copyFrom.m_Byteswap )
  217. {
  218. if(copyFrom.m_Memory.Count() > 0)
  219. {
  220. Assert( false ); // This is a slow path, don't do this.
  221. // copy memory
  222. m_Memory.EnsureCapacity( copyFrom.m_Memory.Count() );
  223. memcpy( m_Memory.Base(), copyFrom.m_Memory.Base(), copyFrom.m_Memory.Count() );
  224. }
  225. }
  226. CUtlBuffer& CUtlBuffer::operator=( const CUtlBuffer& copyFrom )
  227. {
  228. if ( copyFrom.m_Memory.Count() > 0 )
  229. {
  230. Assert( false ); // This is a slow path, don't do this.
  231. if(this != &copyFrom)
  232. {
  233. m_Memory.Purge();
  234. m_Memory.EnsureCapacity( copyFrom.m_Memory.Count() );
  235. memcpy( m_Memory.Base(), copyFrom.m_Memory.Base(), copyFrom.m_Memory.Count() );
  236. }
  237. }
  238. m_Get = copyFrom.m_Get;
  239. m_Put = copyFrom.m_Put;
  240. m_Error = copyFrom.m_Error;
  241. m_Flags = copyFrom.m_Flags;
  242. m_Reserved = copyFrom.m_Reserved;
  243. #if defined( _GAMECONSOLE )
  244. pad = copyFrom.pad;
  245. #endif
  246. m_nTab = copyFrom.m_nTab;
  247. m_nMaxPut = copyFrom.m_nMaxPut;
  248. m_nOffset = copyFrom.m_nOffset;
  249. m_GetOverflowFunc = copyFrom.m_GetOverflowFunc;
  250. m_PutOverflowFunc = copyFrom.m_PutOverflowFunc;
  251. m_Byteswap = copyFrom.m_Byteswap;
  252. return *this;
  253. }
  254. #if VALVE_CPP11
  255. CUtlBuffer::CUtlBuffer( CUtlBuffer&& moveFrom ) // = default
  256. : m_Memory( Move( moveFrom.m_Memory ) )
  257. , m_Get( Move( moveFrom.m_Get ) )
  258. , m_Put( Move( moveFrom.m_Put ) )
  259. , m_Error( Move( moveFrom.m_Error ) )
  260. , m_Flags( Move( moveFrom.m_Flags ) )
  261. , m_Reserved( Move( moveFrom.m_Reserved ) )
  262. #if defined( _GAMECONSOLE )
  263. , pad( Move( moveFrom.pad ) )
  264. #endif
  265. , m_nTab( Move( moveFrom.m_nTab ) )
  266. , m_nMaxPut( Move( moveFrom.m_nMaxPut ) )
  267. , m_nOffset( Move( moveFrom.m_nOffset ) )
  268. , m_GetOverflowFunc( Move( moveFrom.m_GetOverflowFunc ) )
  269. , m_PutOverflowFunc( Move( moveFrom.m_PutOverflowFunc ) )
  270. , m_Byteswap( Move( moveFrom.m_Byteswap ) )
  271. {}
  272. CUtlBuffer& CUtlBuffer::operator=( CUtlBuffer&& moveFrom ) // = default
  273. {
  274. m_Memory = Move( moveFrom.m_Memory );
  275. m_Get = Move( moveFrom.m_Get );
  276. m_Put = Move( moveFrom.m_Put );
  277. m_Error = Move( moveFrom.m_Error );
  278. m_Flags = Move( moveFrom.m_Flags );
  279. m_Reserved = Move( moveFrom.m_Reserved );
  280. #if defined( _GAMECONSOLE )
  281. pad = Move( moveFrom.pad );
  282. #endif
  283. m_nTab = Move( moveFrom.m_nTab );
  284. m_nMaxPut = Move( moveFrom.m_nMaxPut );
  285. m_nOffset = Move( moveFrom.m_nOffset );
  286. m_GetOverflowFunc = Move( moveFrom.m_GetOverflowFunc );
  287. m_PutOverflowFunc = Move( moveFrom.m_PutOverflowFunc );
  288. m_Byteswap = Move( moveFrom.m_Byteswap );
  289. return *this;
  290. }
  291. #endif
  292. //-----------------------------------------------------------------------------
  293. // Modifies the buffer to be binary or text; Blows away the buffer and the CONTAINS_CRLF value.
  294. //-----------------------------------------------------------------------------
  295. void CUtlBuffer::SetBufferType( bool bIsText, bool bContainsCRLF )
  296. {
  297. #ifdef _DEBUG
  298. // If the buffer is empty, there is no opportunity for this stuff to fail
  299. if ( TellMaxPut() != 0 )
  300. {
  301. if ( IsText() )
  302. {
  303. if ( bIsText )
  304. {
  305. Assert( ContainsCRLF() == bContainsCRLF );
  306. }
  307. else
  308. {
  309. Assert( ContainsCRLF() );
  310. }
  311. }
  312. else
  313. {
  314. if ( bIsText )
  315. {
  316. Assert( bContainsCRLF );
  317. }
  318. }
  319. }
  320. #endif
  321. if ( bIsText )
  322. {
  323. m_Flags |= TEXT_BUFFER;
  324. }
  325. else
  326. {
  327. m_Flags &= ~TEXT_BUFFER;
  328. }
  329. if ( bContainsCRLF )
  330. {
  331. m_Flags |= CONTAINS_CRLF;
  332. }
  333. else
  334. {
  335. m_Flags &= ~CONTAINS_CRLF;
  336. }
  337. }
  338. //-----------------------------------------------------------------------------
  339. // Attaches the buffer to external memory....
  340. //-----------------------------------------------------------------------------
  341. void CUtlBuffer::SetExternalBuffer( void* pMemory, int nSize, int nInitialPut, int nFlags )
  342. {
  343. m_Memory.SetExternalBuffer( (unsigned char*)pMemory, nSize );
  344. // Reset all indices; we just changed memory
  345. m_Get = 0;
  346. m_Put = nInitialPut;
  347. m_nTab = 0;
  348. m_Error = 0;
  349. m_nOffset = 0;
  350. m_Flags = nFlags;
  351. m_nMaxPut = -1;
  352. AddNullTermination( m_Put );
  353. }
  354. //-----------------------------------------------------------------------------
  355. // Assumes an external buffer but manages its deletion
  356. //-----------------------------------------------------------------------------
  357. void CUtlBuffer::AssumeMemory( void *pMemory, int nSize, int nInitialPut, int nFlags )
  358. {
  359. m_Memory.AssumeMemory( (unsigned char*) pMemory, nSize );
  360. // Reset all indices; we just changed memory
  361. m_Get = 0;
  362. m_Put = nInitialPut;
  363. m_nTab = 0;
  364. m_Error = 0;
  365. m_nOffset = 0;
  366. m_Flags = nFlags;
  367. m_nMaxPut = -1;
  368. AddNullTermination( m_Put );
  369. }
  370. //-----------------------------------------------------------------------------
  371. // Allows the caller to control memory
  372. //-----------------------------------------------------------------------------
  373. void* CUtlBuffer::DetachMemory()
  374. {
  375. // Reset all indices; we just changed memory
  376. m_Get = 0;
  377. m_Put = 0;
  378. m_nTab = 0;
  379. m_Error = 0;
  380. m_nOffset = 0;
  381. return m_Memory.DetachMemory( );
  382. }
  383. //-----------------------------------------------------------------------------
  384. // Makes sure we've got at least this much memory
  385. //-----------------------------------------------------------------------------
  386. void CUtlBuffer::EnsureCapacity( int num )
  387. {
  388. MEM_ALLOC_CREDIT();
  389. // Add one extra for the null termination
  390. num += 1;
  391. if ( m_Memory.IsExternallyAllocated() )
  392. {
  393. if ( IsGrowable() && ( m_Memory.NumAllocated() < num ) )
  394. {
  395. m_Memory.ConvertToGrowableMemory( 0 );
  396. }
  397. else
  398. {
  399. num -= 1;
  400. }
  401. }
  402. m_Memory.EnsureCapacity( num );
  403. }
  404. //-----------------------------------------------------------------------------
  405. // Base get method from which all others derive
  406. //-----------------------------------------------------------------------------
  407. bool CUtlBuffer::Get( void* pMem, int size )
  408. {
  409. if ( size > 0 && CheckGet( size ) )
  410. {
  411. memcpy( pMem, &m_Memory[m_Get - m_nOffset], size );
  412. m_Get += size;
  413. return true;
  414. }
  415. return false;
  416. }
  417. //-----------------------------------------------------------------------------
  418. // This will get at least 1 byte and up to nSize bytes.
  419. // It will return the number of bytes actually read.
  420. //-----------------------------------------------------------------------------
  421. int CUtlBuffer::GetUpTo( void *pMem, int nSize )
  422. {
  423. if ( CheckArbitraryPeekGet( 0, nSize ) )
  424. {
  425. memcpy( pMem, &m_Memory[m_Get - m_nOffset], nSize );
  426. m_Get += nSize;
  427. return nSize;
  428. }
  429. return 0;
  430. }
  431. //-----------------------------------------------------------------------------
  432. // Eats whitespace
  433. //-----------------------------------------------------------------------------
  434. void CUtlBuffer::EatWhiteSpace()
  435. {
  436. if ( IsText() && IsValid() )
  437. {
  438. while ( CheckGet( sizeof(char) ) )
  439. {
  440. if ( !V_isspace( *(const unsigned char*)PeekGet() ) )
  441. break;
  442. m_Get += sizeof(char);
  443. }
  444. }
  445. }
  446. //-----------------------------------------------------------------------------
  447. // Eats C++ style comments
  448. //-----------------------------------------------------------------------------
  449. bool CUtlBuffer::EatCPPComment()
  450. {
  451. if ( IsText() && IsValid() )
  452. {
  453. // If we don't have a a c++ style comment next, we're done
  454. const char *pPeek = (const char *)PeekGet( 2 * sizeof(char), 0 );
  455. if ( !pPeek || ( pPeek[0] != '/' ) || ( pPeek[1] != '/' ) )
  456. return false;
  457. // Deal with c++ style comments
  458. m_Get += 2;
  459. // read complete line
  460. for ( char c = GetChar(); IsValid(); c = GetChar() )
  461. {
  462. if ( c == '\n' )
  463. break;
  464. }
  465. return true;
  466. }
  467. return false;
  468. }
  469. //-----------------------------------------------------------------------------
  470. // Peeks how much whitespace to eat
  471. //-----------------------------------------------------------------------------
  472. int CUtlBuffer::PeekWhiteSpace( int nOffset )
  473. {
  474. if ( !IsText() || !IsValid() )
  475. return 0;
  476. while ( CheckPeekGet( nOffset, sizeof(char) ) )
  477. {
  478. if ( !V_isspace( *(unsigned char*)PeekGet( nOffset ) ) )
  479. break;
  480. nOffset += sizeof(char);
  481. }
  482. return nOffset;
  483. }
  484. //-----------------------------------------------------------------------------
  485. // Peek size of sting to come, check memory bound
  486. //-----------------------------------------------------------------------------
  487. int CUtlBuffer::PeekStringLength()
  488. {
  489. if ( !IsValid() )
  490. return 0;
  491. // Eat preceeding whitespace
  492. int nOffset = 0;
  493. if ( IsText() )
  494. {
  495. nOffset = PeekWhiteSpace( nOffset );
  496. }
  497. int nStartingOffset = nOffset;
  498. do
  499. {
  500. int nPeekAmount = 128;
  501. // NOTE: Add 1 for the terminating zero!
  502. if ( !CheckArbitraryPeekGet( nOffset, nPeekAmount ) )
  503. {
  504. if ( nOffset == nStartingOffset )
  505. return 0;
  506. return nOffset - nStartingOffset + 1;
  507. }
  508. const char *pTest = (const char *)PeekGet( nOffset );
  509. if ( !IsText() )
  510. {
  511. for ( int i = 0; i < nPeekAmount; ++i )
  512. {
  513. // The +1 here is so we eat the terminating 0
  514. if ( pTest[i] == 0 )
  515. return (i + nOffset - nStartingOffset + 1);
  516. }
  517. }
  518. else
  519. {
  520. for ( int i = 0; i < nPeekAmount; ++i )
  521. {
  522. // The +1 here is so we eat the terminating 0
  523. if ( V_isspace((unsigned char)pTest[i]) || (pTest[i] == 0) )
  524. return (i + nOffset - nStartingOffset + 1);
  525. }
  526. }
  527. nOffset += nPeekAmount;
  528. } while ( true );
  529. }
  530. //-----------------------------------------------------------------------------
  531. // Peek size of line to come, check memory bound
  532. //-----------------------------------------------------------------------------
  533. int CUtlBuffer::PeekLineLength()
  534. {
  535. if ( !IsValid() )
  536. return 0;
  537. int nOffset = 0;
  538. int nStartingOffset = nOffset;
  539. do
  540. {
  541. int nPeekAmount = 128;
  542. // NOTE: Add 1 for the terminating zero!
  543. if ( !CheckArbitraryPeekGet( nOffset, nPeekAmount ) )
  544. {
  545. if ( nOffset == nStartingOffset )
  546. return 0;
  547. return nOffset - nStartingOffset + 1;
  548. }
  549. const char *pTest = (const char *)PeekGet( nOffset );
  550. for ( int i = 0; i < nPeekAmount; ++i )
  551. {
  552. // The +2 here is so we eat the terminating '\n' and 0
  553. if ( pTest[i] == '\n' || pTest[i] == '\r' )
  554. return (i + nOffset - nStartingOffset + 2);
  555. // The +1 here is so we eat the terminating 0
  556. if ( pTest[i] == 0 )
  557. return (i + nOffset - nStartingOffset + 1);
  558. }
  559. nOffset += nPeekAmount;
  560. } while ( true );
  561. }
  562. //-----------------------------------------------------------------------------
  563. // Does the next bytes of the buffer match a pattern?
  564. //-----------------------------------------------------------------------------
  565. bool CUtlBuffer::PeekStringMatch( int nOffset, const char *pString, int nLen )
  566. {
  567. if ( !CheckPeekGet( nOffset, nLen ) )
  568. return false;
  569. return !V_strncmp( (const char*)PeekGet(nOffset), pString, nLen );
  570. }
  571. //-----------------------------------------------------------------------------
  572. // This version of PeekStringLength converts \" to \\ and " to \, etc.
  573. // It also reads a " at the beginning and end of the string
  574. //-----------------------------------------------------------------------------
  575. int CUtlBuffer::PeekDelimitedStringLength( CUtlCharConversion *pConv, bool bActualSize )
  576. {
  577. if ( !IsText() || !pConv )
  578. return PeekStringLength();
  579. // Eat preceeding whitespace
  580. int nOffset = 0;
  581. if ( IsText() )
  582. {
  583. nOffset = PeekWhiteSpace( nOffset );
  584. }
  585. if ( !PeekStringMatch( nOffset, pConv->GetDelimiter(), pConv->GetDelimiterLength() ) )
  586. return 0;
  587. // Try to read ending ", but don't accept \"
  588. int nActualStart = nOffset;
  589. nOffset += pConv->GetDelimiterLength();
  590. int nLen = 1; // Starts at 1 for the '\0' termination
  591. do
  592. {
  593. if ( PeekStringMatch( nOffset, pConv->GetDelimiter(), pConv->GetDelimiterLength() ) )
  594. break;
  595. if ( !CheckPeekGet( nOffset, 1 ) )
  596. break;
  597. char c = *(const char*)PeekGet( nOffset );
  598. ++nLen;
  599. ++nOffset;
  600. if ( c == pConv->GetEscapeChar() )
  601. {
  602. int nLength = pConv->MaxConversionLength();
  603. if ( !CheckArbitraryPeekGet( nOffset, nLength ) )
  604. break;
  605. pConv->FindConversion( (const char*)PeekGet(nOffset), &nLength );
  606. nOffset += nLength;
  607. }
  608. } while (true);
  609. return bActualSize ? nLen : nOffset - nActualStart + pConv->GetDelimiterLength() + 1;
  610. }
  611. //-----------------------------------------------------------------------------
  612. // Reads a null-terminated string
  613. //-----------------------------------------------------------------------------
  614. void CUtlBuffer::GetString( char* pString, int nMaxChars )
  615. {
  616. if (!IsValid())
  617. {
  618. *pString = 0;
  619. return;
  620. }
  621. Assert( nMaxChars > 0 );
  622. if ( nMaxChars <= 0 )
  623. {
  624. return;
  625. }
  626. // Remember, this *includes* the null character
  627. // It will be 0, however, if the buffer is empty.
  628. int nLen = PeekStringLength();
  629. if ( IsText() )
  630. {
  631. EatWhiteSpace();
  632. }
  633. if ( nLen <= 0 )
  634. {
  635. *pString = 0;
  636. m_Error |= GET_OVERFLOW;
  637. return;
  638. }
  639. const int nCharsToRead = Min( nLen, nMaxChars ) - 1;
  640. Get( pString, nCharsToRead );
  641. pString[ nCharsToRead ] = 0;
  642. if ( nLen > ( nCharsToRead + 1 ) )
  643. {
  644. SeekGet( SEEK_CURRENT, nLen - ( nCharsToRead + 1 ) );
  645. }
  646. // Read the terminating NULL in binary formats
  647. if ( !IsText() )
  648. {
  649. VerifyEquals( GetChar(), 0 );
  650. }
  651. }
  652. //-----------------------------------------------------------------------------
  653. // Reads up to and including the first \n
  654. //-----------------------------------------------------------------------------
  655. void CUtlBuffer::GetLine( char* pLine, int nMaxChars )
  656. {
  657. //Assert( IsText() && !ContainsCRLF() );
  658. if ( !IsValid() )
  659. {
  660. *pLine = 0;
  661. return;
  662. }
  663. if ( nMaxChars == 0 )
  664. {
  665. nMaxChars = INT_MAX;
  666. }
  667. // Remember, this *includes* the null character
  668. // It will be 0, however, if the buffer is empty.
  669. int nLen = PeekLineLength();
  670. if ( nLen == 0 )
  671. {
  672. *pLine = 0;
  673. m_Error |= GET_OVERFLOW;
  674. return;
  675. }
  676. // Strip off the terminating NULL
  677. if ( nLen <= nMaxChars )
  678. {
  679. Get( pLine, nLen - 1 );
  680. pLine[ nLen - 1 ] = 0;
  681. }
  682. else
  683. {
  684. Get( pLine, nMaxChars - 1 );
  685. pLine[ nMaxChars - 1 ] = 0;
  686. SeekGet( SEEK_CURRENT, nLen - 1 - nMaxChars );
  687. }
  688. }
  689. //-----------------------------------------------------------------------------
  690. // This version of GetString converts \ to \\ and " to \", etc.
  691. // It also places " at the beginning and end of the string
  692. //-----------------------------------------------------------------------------
  693. char CUtlBuffer::GetDelimitedCharInternal( CUtlCharConversion *pConv )
  694. {
  695. char c = GetChar();
  696. if ( c == pConv->GetEscapeChar() )
  697. {
  698. int nLength = pConv->MaxConversionLength();
  699. if ( !CheckArbitraryPeekGet( 0, nLength ) )
  700. return '\0';
  701. c = pConv->FindConversion( (const char *)PeekGet(), &nLength );
  702. SeekGet( SEEK_CURRENT, nLength );
  703. }
  704. return c;
  705. }
  706. char CUtlBuffer::GetDelimitedChar( CUtlCharConversion *pConv )
  707. {
  708. if ( !IsText() || !pConv )
  709. return GetChar( );
  710. return GetDelimitedCharInternal( pConv );
  711. }
  712. void CUtlBuffer::GetDelimitedString( CUtlCharConversion *pConv, char *pString, int nMaxChars )
  713. {
  714. if ( !IsText() || !pConv )
  715. {
  716. GetString( pString, nMaxChars );
  717. return;
  718. }
  719. if (!IsValid())
  720. {
  721. *pString = 0;
  722. return;
  723. }
  724. if ( nMaxChars == 0 )
  725. {
  726. nMaxChars = INT_MAX;
  727. }
  728. EatWhiteSpace();
  729. if ( !PeekStringMatch( 0, pConv->GetDelimiter(), pConv->GetDelimiterLength() ) )
  730. return;
  731. // Pull off the starting delimiter
  732. SeekGet( SEEK_CURRENT, pConv->GetDelimiterLength() );
  733. int nRead = 0;
  734. while ( IsValid() )
  735. {
  736. if ( PeekStringMatch( 0, pConv->GetDelimiter(), pConv->GetDelimiterLength() ) )
  737. {
  738. SeekGet( SEEK_CURRENT, pConv->GetDelimiterLength() );
  739. break;
  740. }
  741. char c = GetDelimitedCharInternal( pConv );
  742. if ( nRead < nMaxChars )
  743. {
  744. pString[nRead] = c;
  745. ++nRead;
  746. }
  747. }
  748. if ( nRead >= nMaxChars )
  749. {
  750. nRead = nMaxChars - 1;
  751. }
  752. pString[nRead] = '\0';
  753. }
  754. //-----------------------------------------------------------------------------
  755. // Checks if a get is ok
  756. //-----------------------------------------------------------------------------
  757. bool CUtlBuffer::CheckGet( int nSize )
  758. {
  759. if ( m_Error & GET_OVERFLOW )
  760. return false;
  761. if ( TellMaxPut() < m_Get + nSize )
  762. {
  763. m_Error |= GET_OVERFLOW;
  764. return false;
  765. }
  766. if ( ( m_Get < m_nOffset ) || ( m_Memory.NumAllocated() < m_Get - m_nOffset + nSize ) )
  767. {
  768. if ( !OnGetOverflow( nSize ) )
  769. {
  770. m_Error |= GET_OVERFLOW;
  771. return false;
  772. }
  773. }
  774. return true;
  775. }
  776. //-----------------------------------------------------------------------------
  777. // Checks if a peek get is ok
  778. //-----------------------------------------------------------------------------
  779. bool CUtlBuffer::CheckPeekGet( int nOffset, int nSize )
  780. {
  781. if ( m_Error & GET_OVERFLOW )
  782. return false;
  783. // Checking for peek can't set the overflow flag
  784. bool bOk = CheckGet( nOffset + nSize );
  785. m_Error &= ~GET_OVERFLOW;
  786. return bOk;
  787. }
  788. //-----------------------------------------------------------------------------
  789. // Call this to peek arbitrarily long into memory. It doesn't fail unless
  790. // it can't read *anything* new
  791. //-----------------------------------------------------------------------------
  792. bool CUtlBuffer::CheckArbitraryPeekGet( int nOffset, int &nIncrement )
  793. {
  794. if ( TellGet() + nOffset >= TellMaxPut() )
  795. {
  796. nIncrement = 0;
  797. return false;
  798. }
  799. if ( TellGet() + nOffset + nIncrement > TellMaxPut() )
  800. {
  801. nIncrement = TellMaxPut() - TellGet() - nOffset;
  802. }
  803. // NOTE: CheckPeekGet could modify TellMaxPut for streaming files
  804. // We have to call TellMaxPut again here
  805. CheckPeekGet( nOffset, nIncrement );
  806. int nMaxGet = TellMaxPut() - TellGet();
  807. if ( nMaxGet < nIncrement )
  808. {
  809. nIncrement = nMaxGet;
  810. }
  811. return (nIncrement != 0);
  812. }
  813. //-----------------------------------------------------------------------------
  814. // Peek part of the butt
  815. //-----------------------------------------------------------------------------
  816. const void* CUtlBuffer::PeekGet( int nMaxSize, int nOffset )
  817. {
  818. if ( !CheckPeekGet( nOffset, nMaxSize ) )
  819. return NULL;
  820. return &m_Memory[ m_Get + nOffset - m_nOffset ];
  821. }
  822. //-----------------------------------------------------------------------------
  823. // Change where I'm reading
  824. //-----------------------------------------------------------------------------
  825. void CUtlBuffer::SeekGet( SeekType_t type, int offset )
  826. {
  827. switch( type )
  828. {
  829. case SEEK_HEAD:
  830. m_Get = offset;
  831. break;
  832. case SEEK_CURRENT:
  833. m_Get += offset;
  834. break;
  835. case SEEK_TAIL:
  836. m_Get = m_nMaxPut - offset;
  837. break;
  838. }
  839. if ( m_Get > m_nMaxPut )
  840. {
  841. m_Error |= GET_OVERFLOW;
  842. }
  843. else
  844. {
  845. m_Error &= ~GET_OVERFLOW;
  846. if ( m_Get < m_nOffset || m_Get >= m_nOffset + Size() )
  847. {
  848. OnGetOverflow( -1 );
  849. }
  850. }
  851. }
  852. //-----------------------------------------------------------------------------
  853. // Parse...
  854. //-----------------------------------------------------------------------------
  855. #pragma warning ( disable : 4706 )
  856. int CUtlBuffer::VaScanf( const char* pFmt, va_list list )
  857. {
  858. Assert( pFmt );
  859. if ( m_Error || !IsText() )
  860. return 0;
  861. int numScanned = 0;
  862. char c;
  863. while ( c = *pFmt++ )
  864. {
  865. // Stop if we hit the end of the buffer
  866. if ( m_Get >= TellMaxPut() )
  867. {
  868. m_Error |= GET_OVERFLOW;
  869. break;
  870. }
  871. switch (c)
  872. {
  873. case ' ':
  874. // eat all whitespace
  875. EatWhiteSpace();
  876. break;
  877. case '%':
  878. {
  879. // Conversion character... try to convert baby!
  880. char type = *pFmt++;
  881. if (type == 0)
  882. return numScanned;
  883. switch(type)
  884. {
  885. case 'c':
  886. {
  887. char* ch = va_arg( list, char * );
  888. if ( CheckPeekGet( 0, sizeof(char) ) )
  889. {
  890. *ch = *(const char*)PeekGet();
  891. ++m_Get;
  892. }
  893. else
  894. {
  895. *ch = 0;
  896. return numScanned;
  897. }
  898. }
  899. break;
  900. case 'h':
  901. {
  902. if ( *pFmt == 'd' || *pFmt == 'i' )
  903. {
  904. if ( !GetTypeText( *va_arg( list, int16 * ) ) )
  905. return numScanned; // only support short ints, don't bother with hex
  906. }
  907. else if ( *pFmt == 'u' )
  908. {
  909. if ( !GetTypeText( *va_arg( list, uint16 * ) ) )
  910. return numScanned;
  911. }
  912. else
  913. return numScanned;
  914. ++pFmt;
  915. }
  916. break;
  917. case 'I':
  918. {
  919. if ( *pFmt++ != '6' || *pFmt++ != '4' )
  920. return numScanned; // only support "I64d" and "I64u"
  921. if ( *pFmt == 'd' )
  922. {
  923. if ( !GetTypeText( *va_arg( list, int64 * ) ) )
  924. return numScanned;
  925. }
  926. else if ( *pFmt == 'u' )
  927. {
  928. if ( !GetTypeText( *va_arg( list, uint64 * ) ) )
  929. return numScanned;
  930. }
  931. else
  932. {
  933. return numScanned;
  934. }
  935. ++pFmt;
  936. }
  937. break;
  938. case 'i':
  939. case 'd':
  940. {
  941. int32 *pArg = va_arg( list, int32 * );
  942. if ( !GetTypeText( *pArg ) )
  943. return numScanned;
  944. }
  945. break;
  946. case 'x':
  947. {
  948. uint32 *pArg = va_arg( list, uint32 * );
  949. if ( !GetTypeText( *pArg, 16 ) )
  950. return numScanned;
  951. }
  952. break;
  953. case 'u':
  954. {
  955. uint32 *pArg = va_arg( list, uint32 * );
  956. if ( !GetTypeText( *pArg ) )
  957. return numScanned;
  958. }
  959. break;
  960. case 'l':
  961. {
  962. // we currently support %lf and %lld
  963. if ( *pFmt == 'f' )
  964. {
  965. if ( !GetTypeText( *va_arg( list, double * ) ) )
  966. return numScanned;
  967. }
  968. else if ( *pFmt == 'l' && *++pFmt == 'd' )
  969. {
  970. if ( !GetTypeText( *va_arg( list, int64 * ) ) )
  971. return numScanned;
  972. }
  973. else
  974. return numScanned;
  975. }
  976. break;
  977. case 'f':
  978. {
  979. float *pArg = va_arg( list, float * );
  980. if ( !GetTypeText( *pArg ) )
  981. return numScanned;
  982. }
  983. break;
  984. case 's':
  985. {
  986. char* s = va_arg( list, char * );
  987. GetString( s, 64 ); // [SECURITY EXPLOIT: Scanf %s should be deprecated as malicious data can overrun stack buffers! Here we'd assume that at least 64 bytes are available on the stack, and even if not this shouldn't give attracker much room for code execution]
  988. }
  989. break;
  990. default:
  991. {
  992. // unimplemented scanf type
  993. Assert(0);
  994. return numScanned;
  995. }
  996. break;
  997. }
  998. ++numScanned;
  999. }
  1000. break;
  1001. default:
  1002. {
  1003. // Here we have to match the format string character
  1004. // against what's in the buffer or we're done.
  1005. if ( !CheckPeekGet( 0, sizeof(char) ) )
  1006. return numScanned;
  1007. if ( c != *(const char*)PeekGet() )
  1008. return numScanned;
  1009. ++m_Get;
  1010. }
  1011. }
  1012. }
  1013. return numScanned;
  1014. }
  1015. #pragma warning ( default : 4706 )
  1016. int CUtlBuffer::Scanf( const char* pFmt, ... )
  1017. {
  1018. va_list args;
  1019. va_start( args, pFmt );
  1020. int count = VaScanf( pFmt, args );
  1021. va_end( args );
  1022. return count;
  1023. }
  1024. //-----------------------------------------------------------------------------
  1025. // Advance the get index until after the particular string is found
  1026. // Do not eat whitespace before starting. Return false if it failed
  1027. //-----------------------------------------------------------------------------
  1028. bool CUtlBuffer::GetToken( const char *pToken )
  1029. {
  1030. Assert( pToken );
  1031. // Look for the token
  1032. int nLen = V_strlen( pToken );
  1033. // First time through on streaming, check what we already have loaded
  1034. // if we have enough loaded to do the check
  1035. int nMaxSize = Size() - ( TellGet() - m_nOffset );
  1036. if ( nMaxSize <= nLen )
  1037. {
  1038. nMaxSize = Size();
  1039. }
  1040. int nSizeRemaining = TellMaxPut() - TellGet();
  1041. int nGet = TellGet();
  1042. while ( nSizeRemaining >= nLen )
  1043. {
  1044. bool bOverFlow = ( nSizeRemaining > nMaxSize );
  1045. int nSizeToCheck = bOverFlow ? nMaxSize : nSizeRemaining;
  1046. if ( !CheckPeekGet( 0, nSizeToCheck ) )
  1047. break;
  1048. const char *pBufStart = (const char*)PeekGet();
  1049. const char *pFoundEnd = V_strnistr( pBufStart, pToken, nSizeToCheck );
  1050. // Time to be careful: if we are in a state of overflow
  1051. // (namely, there's more of the buffer beyond the current window)
  1052. // we could be looking for 'foo' for example, and find 'foobar'
  1053. // if 'foo' happens to be the last 3 characters of the current window
  1054. size_t nOffset = (size_t)pFoundEnd - (size_t)pBufStart;
  1055. bool bPotentialMismatch = ( bOverFlow && ( (int)nOffset == Size() - nLen ) );
  1056. if ( !pFoundEnd || bPotentialMismatch )
  1057. {
  1058. nSizeRemaining -= nSizeToCheck;
  1059. if ( !pFoundEnd && ( nSizeRemaining < nLen ) )
  1060. break;
  1061. // Second time through, stream as much in as possible
  1062. // But keep the last portion of the current buffer
  1063. // since we couldn't check it against stuff outside the window
  1064. nSizeRemaining += nLen;
  1065. nMaxSize = Size();
  1066. SeekGet( CUtlBuffer::SEEK_CURRENT, nSizeToCheck - nLen );
  1067. continue;
  1068. }
  1069. // Seek past the end of the found string
  1070. SeekGet( CUtlBuffer::SEEK_CURRENT, (int)( nOffset + nLen ) );
  1071. return true;
  1072. }
  1073. // Didn't find a match, leave the get index where it was to start with
  1074. SeekGet( CUtlBuffer::SEEK_HEAD, nGet );
  1075. return false;
  1076. }
  1077. //-----------------------------------------------------------------------------
  1078. // (For text buffers only)
  1079. // Parse a token from the buffer:
  1080. // Grab all text that lies between a starting delimiter + ending delimiter
  1081. // (skipping whitespace that leads + trails both delimiters).
  1082. // Note the delimiter checks are case-insensitive.
  1083. // If successful, the get index is advanced and the function returns true,
  1084. // otherwise the index is not advanced and the function returns false.
  1085. //-----------------------------------------------------------------------------
  1086. bool CUtlBuffer::ParseToken( const char *pStartingDelim, const char *pEndingDelim, char* pString, int nMaxLen )
  1087. {
  1088. int nCharsToCopy = 0;
  1089. int nCurrentGet = 0;
  1090. size_t nEndingDelimLen;
  1091. // Starting delimiter is optional
  1092. char emptyBuf = '\0';
  1093. if ( !pStartingDelim )
  1094. {
  1095. pStartingDelim = &emptyBuf;
  1096. }
  1097. // Ending delimiter is not
  1098. Assert( pEndingDelim && pEndingDelim[0] );
  1099. nEndingDelimLen = V_strlen( pEndingDelim );
  1100. int nStartGet = TellGet();
  1101. char nCurrChar;
  1102. int nTokenStart = -1;
  1103. EatWhiteSpace( );
  1104. while ( *pStartingDelim )
  1105. {
  1106. nCurrChar = *pStartingDelim++;
  1107. if ( !V_isspace((unsigned char)nCurrChar) )
  1108. {
  1109. if ( tolower( GetChar() ) != tolower( nCurrChar ) )
  1110. goto parseFailed;
  1111. }
  1112. else
  1113. {
  1114. EatWhiteSpace();
  1115. }
  1116. }
  1117. EatWhiteSpace();
  1118. nTokenStart = TellGet();
  1119. if ( !GetToken( pEndingDelim ) )
  1120. goto parseFailed;
  1121. nCurrentGet = TellGet();
  1122. nCharsToCopy = (int)( (nCurrentGet - nEndingDelimLen) - nTokenStart );
  1123. if ( nCharsToCopy >= nMaxLen )
  1124. {
  1125. nCharsToCopy = nMaxLen - 1;
  1126. }
  1127. if ( nCharsToCopy > 0 )
  1128. {
  1129. SeekGet( CUtlBuffer::SEEK_HEAD, nTokenStart );
  1130. Get( pString, nCharsToCopy );
  1131. if ( !IsValid() )
  1132. goto parseFailed;
  1133. // Eat trailing whitespace
  1134. for ( ; nCharsToCopy > 0; --nCharsToCopy )
  1135. {
  1136. if ( !V_isspace( (unsigned char)pString[ nCharsToCopy-1 ] ) )
  1137. break;
  1138. }
  1139. }
  1140. pString[ nCharsToCopy ] = '\0';
  1141. // Advance the Get index
  1142. SeekGet( CUtlBuffer::SEEK_HEAD, nCurrentGet );
  1143. return true;
  1144. parseFailed:
  1145. // Revert the get index
  1146. SeekGet( SEEK_HEAD, nStartGet );
  1147. pString[0] = '\0';
  1148. return false;
  1149. }
  1150. //-----------------------------------------------------------------------------
  1151. // Parses the next token, given a set of character breaks to stop at
  1152. //-----------------------------------------------------------------------------
  1153. int CUtlBuffer::ParseToken( characterset_t *pBreaks, char *pTokenBuf, int nMaxLen, bool bParseComments )
  1154. {
  1155. Assert( nMaxLen > 0 );
  1156. pTokenBuf[0] = 0;
  1157. // skip whitespace + comments
  1158. while ( true )
  1159. {
  1160. if ( !IsValid() )
  1161. return -1;
  1162. EatWhiteSpace();
  1163. if ( bParseComments )
  1164. {
  1165. if ( !EatCPPComment() )
  1166. break;
  1167. }
  1168. else
  1169. {
  1170. break;
  1171. }
  1172. }
  1173. char c = GetChar();
  1174. // End of buffer
  1175. if ( c == 0 )
  1176. return -1;
  1177. // handle quoted strings specially
  1178. if ( c == '\"' )
  1179. {
  1180. int nLen = 0;
  1181. while( IsValid() )
  1182. {
  1183. c = GetChar();
  1184. if ( c == '\"' || !c )
  1185. {
  1186. pTokenBuf[nLen] = 0;
  1187. return nLen;
  1188. }
  1189. pTokenBuf[nLen] = c;
  1190. if ( ++nLen == nMaxLen )
  1191. {
  1192. pTokenBuf[nLen-1] = 0;
  1193. return nMaxLen;
  1194. }
  1195. }
  1196. // In this case, we hit the end of the buffer before hitting the end qoute
  1197. pTokenBuf[nLen] = 0;
  1198. return nLen;
  1199. }
  1200. // parse single characters
  1201. if ( IN_CHARACTERSET( *pBreaks, c ) )
  1202. {
  1203. pTokenBuf[0] = c;
  1204. pTokenBuf[1] = 0;
  1205. return 1;
  1206. }
  1207. // parse a regular word
  1208. int nLen = 0;
  1209. while ( true )
  1210. {
  1211. pTokenBuf[nLen] = c;
  1212. if ( ++nLen == nMaxLen )
  1213. {
  1214. pTokenBuf[nLen-1] = 0;
  1215. return nMaxLen;
  1216. }
  1217. c = GetChar();
  1218. if ( !IsValid() )
  1219. break;
  1220. if ( IN_CHARACTERSET( *pBreaks, c ) || c == '\"' || c <= ' ' )
  1221. {
  1222. SeekGet( SEEK_CURRENT, -1 );
  1223. break;
  1224. }
  1225. }
  1226. pTokenBuf[nLen] = 0;
  1227. return nLen;
  1228. }
  1229. //-----------------------------------------------------------------------------
  1230. // Serialization
  1231. //-----------------------------------------------------------------------------
  1232. void CUtlBuffer::Put( const void *pMem, int size )
  1233. {
  1234. if ( size && CheckPut( size ) )
  1235. {
  1236. memcpy( &m_Memory[m_Put - m_nOffset], pMem, size );
  1237. m_Put += size;
  1238. AddNullTermination( m_Put );
  1239. }
  1240. }
  1241. //-----------------------------------------------------------------------------
  1242. // Writes a null-terminated string
  1243. //-----------------------------------------------------------------------------
  1244. void CUtlBuffer::PutString( const char* pString )
  1245. {
  1246. if (!IsText())
  1247. {
  1248. if ( pString )
  1249. {
  1250. // Not text? append a null at the end.
  1251. int nLen = (int)V_strlen( pString ) + 1;
  1252. Put( pString, nLen * sizeof(char) );
  1253. return;
  1254. }
  1255. else
  1256. {
  1257. PutTypeBin<char>( 0 );
  1258. }
  1259. }
  1260. else if (pString)
  1261. {
  1262. int nTabCount = ( m_Flags & AUTO_TABS_DISABLED ) ? 0 : m_nTab;
  1263. if ( nTabCount > 0 )
  1264. {
  1265. if ( WasLastCharacterCR() )
  1266. {
  1267. PutTabs();
  1268. }
  1269. const char* pEndl = strchr( pString, '\n' );
  1270. while ( pEndl )
  1271. {
  1272. size_t nSize = (size_t)pEndl - (size_t)pString + sizeof(char);
  1273. Put( pString, (int)nSize );
  1274. pString = pEndl + 1;
  1275. if ( *pString )
  1276. {
  1277. PutTabs();
  1278. pEndl = strchr( pString, '\n' );
  1279. }
  1280. else
  1281. {
  1282. pEndl = NULL;
  1283. }
  1284. }
  1285. }
  1286. int nLen = (int)V_strlen( pString );
  1287. if ( nLen )
  1288. {
  1289. Put( pString, nLen * sizeof(char) );
  1290. }
  1291. }
  1292. }
  1293. //-----------------------------------------------------------------------------
  1294. // This version of PutString converts \ to \\ and " to \", etc.
  1295. // It also places " at the beginning and end of the string
  1296. //-----------------------------------------------------------------------------
  1297. inline void CUtlBuffer::PutDelimitedCharInternal( CUtlCharConversion *pConv, char c )
  1298. {
  1299. int l = pConv->GetConversionLength( c );
  1300. if ( l == 0 )
  1301. {
  1302. PutChar( c );
  1303. }
  1304. else
  1305. {
  1306. PutChar( pConv->GetEscapeChar() );
  1307. Put( pConv->GetConversionString( c ), l );
  1308. }
  1309. }
  1310. void CUtlBuffer::PutDelimitedChar( CUtlCharConversion *pConv, char c )
  1311. {
  1312. if ( !IsText() || !pConv )
  1313. {
  1314. PutChar( c );
  1315. return;
  1316. }
  1317. PutDelimitedCharInternal( pConv, c );
  1318. }
  1319. void CUtlBuffer::PutDelimitedString( CUtlCharConversion *pConv, const char *pString )
  1320. {
  1321. if ( !IsText() || !pConv )
  1322. {
  1323. PutString( pString );
  1324. return;
  1325. }
  1326. if ( WasLastCharacterCR() )
  1327. {
  1328. PutTabs();
  1329. }
  1330. Put( pConv->GetDelimiter(), pConv->GetDelimiterLength() );
  1331. int nLen = pString ? V_strlen( pString ) : 0;
  1332. for ( int i = 0; i < nLen; ++i )
  1333. {
  1334. PutDelimitedCharInternal( pConv, pString[i] );
  1335. }
  1336. if ( WasLastCharacterCR() )
  1337. {
  1338. PutTabs();
  1339. }
  1340. Put( pConv->GetDelimiter(), pConv->GetDelimiterLength() );
  1341. }
  1342. void CUtlBuffer::VaPrintf( const char* pFmt, va_list list )
  1343. {
  1344. char temp[8192];
  1345. int nLen = V_vsnprintf( temp, sizeof( temp ), pFmt, list );
  1346. ErrorIfNot( nLen < sizeof( temp ), ( "CUtlBuffer::VaPrintf: String overflowed buffer [%d]\n", sizeof( temp ) ) );
  1347. PutString( temp );
  1348. }
  1349. void CUtlBuffer::Printf( const char* pFmt, ... )
  1350. {
  1351. va_list args;
  1352. va_start( args, pFmt );
  1353. VaPrintf( pFmt, args );
  1354. va_end( args );
  1355. }
  1356. //-----------------------------------------------------------------------------
  1357. // Calls the overflow functions
  1358. //-----------------------------------------------------------------------------
  1359. void CUtlBuffer::SetOverflowFuncs( UtlBufferOverflowFunc_t getFunc, UtlBufferOverflowFunc_t putFunc )
  1360. {
  1361. m_GetOverflowFunc = getFunc;
  1362. m_PutOverflowFunc = putFunc;
  1363. }
  1364. //-----------------------------------------------------------------------------
  1365. // Calls the overflow functions
  1366. //-----------------------------------------------------------------------------
  1367. bool CUtlBuffer::OnPutOverflow( int nSize )
  1368. {
  1369. return (this->*m_PutOverflowFunc)( nSize );
  1370. }
  1371. bool CUtlBuffer::OnGetOverflow( int nSize )
  1372. {
  1373. return (this->*m_GetOverflowFunc)( nSize );
  1374. }
  1375. //-----------------------------------------------------------------------------
  1376. // Checks if a put is ok
  1377. //-----------------------------------------------------------------------------
  1378. bool CUtlBuffer::PutOverflow( int nSize )
  1379. {
  1380. MEM_ALLOC_CREDIT();
  1381. if ( m_Memory.IsExternallyAllocated() )
  1382. {
  1383. if ( !IsGrowable() )
  1384. return false;
  1385. m_Memory.ConvertToGrowableMemory( 0 );
  1386. }
  1387. while( Size() < m_Put - m_nOffset + nSize )
  1388. {
  1389. m_Memory.Grow();
  1390. }
  1391. return true;
  1392. }
  1393. bool CUtlBuffer::GetOverflow( int nSize )
  1394. {
  1395. return false;
  1396. }
  1397. //-----------------------------------------------------------------------------
  1398. // Checks if a put is ok
  1399. //-----------------------------------------------------------------------------
  1400. bool CUtlBuffer::CheckPut( int nSize )
  1401. {
  1402. if ( ( m_Error & PUT_OVERFLOW ) || IsReadOnly() )
  1403. return false;
  1404. if ( ( m_Put < m_nOffset ) || ( m_Memory.NumAllocated() < m_Put - m_nOffset + nSize ) )
  1405. {
  1406. if ( !OnPutOverflow( nSize ) )
  1407. {
  1408. m_Error |= PUT_OVERFLOW;
  1409. return false;
  1410. }
  1411. }
  1412. return true;
  1413. }
  1414. void CUtlBuffer::SeekPut( SeekType_t type, int offset )
  1415. {
  1416. int nNextPut = m_Put;
  1417. switch( type )
  1418. {
  1419. case SEEK_HEAD:
  1420. nNextPut = offset;
  1421. break;
  1422. case SEEK_CURRENT:
  1423. nNextPut += offset;
  1424. break;
  1425. case SEEK_TAIL:
  1426. nNextPut = m_nMaxPut - offset;
  1427. break;
  1428. }
  1429. // Force a write of the data
  1430. // FIXME: We could make this more optimal potentially by writing out
  1431. // the entire buffer if you seek outside the current range
  1432. // NOTE: This call will write and will also seek the file to nNextPut.
  1433. OnPutOverflow( -nNextPut-1 );
  1434. m_Put = nNextPut;
  1435. AddNullTermination( m_Put );
  1436. }
  1437. void CUtlBuffer::ActivateByteSwapping( bool bActivate )
  1438. {
  1439. m_Byteswap.ActivateByteSwapping( bActivate );
  1440. }
  1441. void CUtlBuffer::SetBigEndian( bool bigEndian )
  1442. {
  1443. m_Byteswap.SetTargetBigEndian( bigEndian );
  1444. }
  1445. bool CUtlBuffer::IsBigEndian( void )
  1446. {
  1447. return m_Byteswap.IsTargetBigEndian();
  1448. }
  1449. //-----------------------------------------------------------------------------
  1450. // null terminate the buffer
  1451. // NOTE: Pass in nPut here even though it is just a copy of m_Put. This is almost always called immediately
  1452. // after modifying m_Put and this lets it stay in a register and avoid LHS on PPC.
  1453. //-----------------------------------------------------------------------------
  1454. void CUtlBuffer::AddNullTermination( int nPut )
  1455. {
  1456. if ( nPut > m_nMaxPut )
  1457. {
  1458. if ( !IsReadOnly() && ((m_Error & PUT_OVERFLOW) == 0) )
  1459. {
  1460. // Add null termination value
  1461. if ( CheckPut( 1 ) )
  1462. {
  1463. m_Memory[nPut - m_nOffset] = 0;
  1464. }
  1465. else
  1466. {
  1467. // Restore the overflow state, it was valid before...
  1468. m_Error &= ~PUT_OVERFLOW;
  1469. }
  1470. }
  1471. m_nMaxPut = nPut;
  1472. }
  1473. }
  1474. //-----------------------------------------------------------------------------
  1475. // Converts a buffer from a CRLF buffer to a CR buffer (and back)
  1476. // Returns false if no conversion was necessary (and outBuf is left untouched)
  1477. // If the conversion occurs, outBuf will be cleared.
  1478. //-----------------------------------------------------------------------------
  1479. bool CUtlBuffer::ConvertCRLF( CUtlBuffer &outBuf )
  1480. {
  1481. if ( !IsText() || !outBuf.IsText() )
  1482. return false;
  1483. if ( ContainsCRLF() == outBuf.ContainsCRLF() )
  1484. return false;
  1485. int nInCount = TellMaxPut();
  1486. outBuf.Purge();
  1487. outBuf.EnsureCapacity( nInCount );
  1488. bool bFromCRLF = ContainsCRLF();
  1489. // Start reading from the beginning
  1490. int nGet = TellGet();
  1491. int nPut = TellPut();
  1492. int nGetDelta = 0;
  1493. int nPutDelta = 0;
  1494. const char *pBase = (const char*)Base();
  1495. intp nCurrGet = 0;
  1496. while ( nCurrGet < nInCount )
  1497. {
  1498. const char *pCurr = &pBase[nCurrGet];
  1499. if ( bFromCRLF )
  1500. {
  1501. const char *pNext = V_strnistr( pCurr, "\r\n", nInCount - nCurrGet );
  1502. if ( !pNext )
  1503. {
  1504. outBuf.Put( pCurr, nInCount - nCurrGet );
  1505. break;
  1506. }
  1507. intp nBytes = (intp)pNext - (intp)pCurr;
  1508. outBuf.Put( pCurr, (int)nBytes );
  1509. outBuf.PutChar( '\n' );
  1510. nCurrGet += nBytes + 2;
  1511. if ( nGet >= nCurrGet - 1 )
  1512. {
  1513. --nGetDelta;
  1514. }
  1515. if ( nPut >= nCurrGet - 1 )
  1516. {
  1517. --nPutDelta;
  1518. }
  1519. }
  1520. else
  1521. {
  1522. const char *pNext = V_strnchr( pCurr, '\n', nInCount - nCurrGet );
  1523. if ( !pNext )
  1524. {
  1525. outBuf.Put( pCurr, nInCount - nCurrGet );
  1526. break;
  1527. }
  1528. intp nBytes = (intp)pNext - (intp)pCurr;
  1529. outBuf.Put( pCurr, (int)nBytes );
  1530. outBuf.PutChar( '\r' );
  1531. outBuf.PutChar( '\n' );
  1532. nCurrGet += nBytes + 1;
  1533. if ( nGet >= nCurrGet )
  1534. {
  1535. ++nGetDelta;
  1536. }
  1537. if ( nPut >= nCurrGet )
  1538. {
  1539. ++nPutDelta;
  1540. }
  1541. }
  1542. }
  1543. Assert( nPut + nPutDelta <= outBuf.TellMaxPut() );
  1544. outBuf.SeekGet( SEEK_HEAD, nGet + nGetDelta );
  1545. outBuf.SeekPut( SEEK_HEAD, nPut + nPutDelta );
  1546. return true;
  1547. }
  1548. //-----------------------------------------------------------------------------
  1549. // Fast swap
  1550. //-----------------------------------------------------------------------------
  1551. void CUtlBuffer::Swap( CUtlBuffer &buf )
  1552. {
  1553. V_swap( m_Get, buf.m_Get );
  1554. V_swap( m_Put, buf.m_Put );
  1555. V_swap( m_nMaxPut, buf.m_nMaxPut );
  1556. V_swap( m_Error, buf.m_Error );
  1557. m_Memory.Swap( buf.m_Memory );
  1558. }
  1559. //-----------------------------------------------------------------------------
  1560. // Fast swap w/ a CUtlMemory.
  1561. //-----------------------------------------------------------------------------
  1562. void CUtlBuffer::Swap( CUtlMemory<uint8> &mem )
  1563. {
  1564. m_Get = 0;
  1565. m_Put = mem.Count();
  1566. m_nMaxPut = mem.Count();
  1567. m_Error = 0;
  1568. m_Memory.Swap( mem );
  1569. }
  1570. //---------------------------------------------------------------------------
  1571. // Implementation of CUtlInplaceBuffer
  1572. //---------------------------------------------------------------------------
  1573. CUtlInplaceBuffer::CUtlInplaceBuffer( int growSize /* = 0 */, int initSize /* = 0 */, int nFlags /* = 0 */ ) :
  1574. CUtlBuffer( growSize, initSize, nFlags )
  1575. {
  1576. }
  1577. bool CUtlInplaceBuffer::InplaceGetLinePtr( char **ppszInBufferPtr, int *pnLineLength )
  1578. {
  1579. Assert( IsText() && !ContainsCRLF() );
  1580. int nLineLen = PeekLineLength();
  1581. if ( nLineLen <= 1 )
  1582. {
  1583. SeekGet( SEEK_TAIL, 0 );
  1584. return false;
  1585. }
  1586. -- nLineLen; // because it accounts for putting a terminating null-character
  1587. char *pszLine = ( char * ) const_cast< void * >( PeekGet() );
  1588. SeekGet( SEEK_CURRENT, nLineLen );
  1589. // Set the out args
  1590. if ( ppszInBufferPtr )
  1591. *ppszInBufferPtr = pszLine;
  1592. if ( pnLineLength )
  1593. *pnLineLength = nLineLen;
  1594. return true;
  1595. }
  1596. char * CUtlInplaceBuffer::InplaceGetLinePtr( void )
  1597. {
  1598. char *pszLine = NULL;
  1599. int nLineLen = 0;
  1600. if ( InplaceGetLinePtr( &pszLine, &nLineLen ) )
  1601. {
  1602. Assert( nLineLen >= 1 );
  1603. switch ( pszLine[ nLineLen - 1 ] )
  1604. {
  1605. case '\n':
  1606. case '\r':
  1607. pszLine[ nLineLen - 1 ] = 0;
  1608. if ( -- nLineLen )
  1609. {
  1610. switch ( pszLine[ nLineLen - 1 ] )
  1611. {
  1612. case '\n':
  1613. case '\r':
  1614. pszLine[ nLineLen - 1 ] = 0;
  1615. break;
  1616. }
  1617. }
  1618. break;
  1619. default:
  1620. Assert( pszLine[ nLineLen ] == 0 );
  1621. break;
  1622. }
  1623. }
  1624. return pszLine;
  1625. }