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.

1796 lines
41 KiB

  1. //========= Copyright 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 = Q_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 = Q_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 ( !Q_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();
  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 = nSize;
  194. }
  195. else
  196. {
  197. m_nMaxPut = -1;
  198. AddNullTermination();
  199. }
  200. SetOverflowFuncs( &CUtlBuffer::GetOverflow, &CUtlBuffer::PutOverflow );
  201. }
  202. //-----------------------------------------------------------------------------
  203. // Modifies the buffer to be binary or text; Blows away the buffer and the CONTAINS_CRLF value.
  204. //-----------------------------------------------------------------------------
  205. void CUtlBuffer::SetBufferType( bool bIsText, bool bContainsCRLF )
  206. {
  207. #ifdef _DEBUG
  208. // If the buffer is empty, there is no opportunity for this stuff to fail
  209. if ( TellMaxPut() != 0 )
  210. {
  211. if ( IsText() )
  212. {
  213. if ( bIsText )
  214. {
  215. Assert( ContainsCRLF() == bContainsCRLF );
  216. }
  217. else
  218. {
  219. Assert( ContainsCRLF() );
  220. }
  221. }
  222. else
  223. {
  224. if ( bIsText )
  225. {
  226. Assert( bContainsCRLF );
  227. }
  228. }
  229. }
  230. #endif
  231. if ( bIsText )
  232. {
  233. m_Flags |= TEXT_BUFFER;
  234. }
  235. else
  236. {
  237. m_Flags &= ~TEXT_BUFFER;
  238. }
  239. if ( bContainsCRLF )
  240. {
  241. m_Flags |= CONTAINS_CRLF;
  242. }
  243. else
  244. {
  245. m_Flags &= ~CONTAINS_CRLF;
  246. }
  247. }
  248. //-----------------------------------------------------------------------------
  249. // Attaches the buffer to external memory....
  250. //-----------------------------------------------------------------------------
  251. void CUtlBuffer::SetExternalBuffer( void* pMemory, int nSize, int nInitialPut, int nFlags )
  252. {
  253. m_Memory.SetExternalBuffer( (unsigned char*)pMemory, nSize );
  254. // Reset all indices; we just changed memory
  255. m_Get = 0;
  256. m_Put = nInitialPut;
  257. m_nTab = 0;
  258. m_Error = 0;
  259. m_nOffset = 0;
  260. m_Flags = nFlags;
  261. m_nMaxPut = -1;
  262. AddNullTermination();
  263. }
  264. //-----------------------------------------------------------------------------
  265. // Assumes an external buffer but manages its deletion
  266. //-----------------------------------------------------------------------------
  267. void CUtlBuffer::AssumeMemory( void *pMemory, int nSize, int nInitialPut, int nFlags )
  268. {
  269. m_Memory.AssumeMemory( (unsigned char*) pMemory, nSize );
  270. // Reset all indices; we just changed memory
  271. m_Get = 0;
  272. m_Put = nInitialPut;
  273. m_nTab = 0;
  274. m_Error = 0;
  275. m_nOffset = 0;
  276. m_Flags = nFlags;
  277. m_nMaxPut = -1;
  278. AddNullTermination();
  279. }
  280. //-----------------------------------------------------------------------------
  281. // Makes sure we've got at least this much memory
  282. //-----------------------------------------------------------------------------
  283. void CUtlBuffer::EnsureCapacity( int num )
  284. {
  285. MEM_ALLOC_CREDIT();
  286. // Add one extra for the null termination
  287. num += 1;
  288. if ( m_Memory.IsExternallyAllocated() )
  289. {
  290. if ( IsGrowable() && ( m_Memory.NumAllocated() < num ) )
  291. {
  292. m_Memory.ConvertToGrowableMemory( 0 );
  293. }
  294. else
  295. {
  296. num -= 1;
  297. }
  298. }
  299. m_Memory.EnsureCapacity( num );
  300. }
  301. //-----------------------------------------------------------------------------
  302. // Base get method from which all others derive
  303. //-----------------------------------------------------------------------------
  304. void CUtlBuffer::Get( void* pMem, int size )
  305. {
  306. if ( size > 0 && CheckGet( size ) )
  307. {
  308. int Index = m_Get - m_nOffset;
  309. Assert( m_Memory.IsIdxValid( Index ) && m_Memory.IsIdxValid( Index + size - 1 ) );
  310. memcpy( pMem, &m_Memory[ Index ], size );
  311. m_Get += size;
  312. }
  313. }
  314. //-----------------------------------------------------------------------------
  315. // This will get at least 1 byte and up to nSize bytes.
  316. // It will return the number of bytes actually read.
  317. //-----------------------------------------------------------------------------
  318. int CUtlBuffer::GetUpTo( void *pMem, int nSize )
  319. {
  320. if ( CheckArbitraryPeekGet( 0, nSize ) )
  321. {
  322. int Index = m_Get - m_nOffset;
  323. Assert( m_Memory.IsIdxValid( Index ) && m_Memory.IsIdxValid( Index + nSize - 1 ) );
  324. memcpy( pMem, &m_Memory[ Index ], nSize );
  325. m_Get += nSize;
  326. return nSize;
  327. }
  328. return 0;
  329. }
  330. //-----------------------------------------------------------------------------
  331. // Eats whitespace
  332. //-----------------------------------------------------------------------------
  333. void CUtlBuffer::EatWhiteSpace()
  334. {
  335. if ( IsText() && IsValid() )
  336. {
  337. while ( CheckGet( sizeof(char) ) )
  338. {
  339. if ( !isspace( *(const unsigned char*)PeekGet() ) )
  340. break;
  341. m_Get += sizeof(char);
  342. }
  343. }
  344. }
  345. //-----------------------------------------------------------------------------
  346. // Eats C++ style comments
  347. //-----------------------------------------------------------------------------
  348. bool CUtlBuffer::EatCPPComment()
  349. {
  350. if ( IsText() && IsValid() )
  351. {
  352. // If we don't have a a c++ style comment next, we're done
  353. const char *pPeek = (const char *)PeekGet( 2 * sizeof(char), 0 );
  354. if ( !pPeek || ( pPeek[0] != '/' ) || ( pPeek[1] != '/' ) )
  355. return false;
  356. // Deal with c++ style comments
  357. m_Get += 2;
  358. // read complete line
  359. for ( char c = GetChar(); IsValid(); c = GetChar() )
  360. {
  361. if ( c == '\n' )
  362. break;
  363. }
  364. return true;
  365. }
  366. return false;
  367. }
  368. //-----------------------------------------------------------------------------
  369. // Peeks how much whitespace to eat
  370. //-----------------------------------------------------------------------------
  371. int CUtlBuffer::PeekWhiteSpace( int nOffset )
  372. {
  373. if ( !IsText() || !IsValid() )
  374. return 0;
  375. while ( CheckPeekGet( nOffset, sizeof(char) ) )
  376. {
  377. if ( !isspace( *(unsigned char*)PeekGet( nOffset ) ) )
  378. break;
  379. nOffset += sizeof(char);
  380. }
  381. return nOffset;
  382. }
  383. //-----------------------------------------------------------------------------
  384. // Peek size of sting to come, check memory bound
  385. //-----------------------------------------------------------------------------
  386. int CUtlBuffer::PeekStringLength()
  387. {
  388. if ( !IsValid() )
  389. return 0;
  390. // Eat preceeding whitespace
  391. int nOffset = 0;
  392. if ( IsText() )
  393. {
  394. nOffset = PeekWhiteSpace( nOffset );
  395. }
  396. int nStartingOffset = nOffset;
  397. do
  398. {
  399. int nPeekAmount = 128;
  400. // NOTE: Add 1 for the terminating zero!
  401. if ( !CheckArbitraryPeekGet( nOffset, nPeekAmount ) )
  402. {
  403. if ( nOffset == nStartingOffset )
  404. return 0;
  405. return nOffset - nStartingOffset + 1;
  406. }
  407. const char *pTest = (const char *)PeekGet( nOffset );
  408. if ( !IsText() )
  409. {
  410. for ( int i = 0; i < nPeekAmount; ++i )
  411. {
  412. // The +1 here is so we eat the terminating 0
  413. if ( pTest[i] == 0 )
  414. return (i + nOffset - nStartingOffset + 1);
  415. }
  416. }
  417. else
  418. {
  419. for ( int i = 0; i < nPeekAmount; ++i )
  420. {
  421. // The +1 here is so we eat the terminating 0
  422. if ( isspace((unsigned char)pTest[i]) || (pTest[i] == 0) )
  423. return (i + nOffset - nStartingOffset + 1);
  424. }
  425. }
  426. nOffset += nPeekAmount;
  427. } while ( true );
  428. }
  429. //-----------------------------------------------------------------------------
  430. // Peek size of line to come, check memory bound
  431. //-----------------------------------------------------------------------------
  432. int CUtlBuffer::PeekLineLength()
  433. {
  434. if ( !IsValid() )
  435. return 0;
  436. int nOffset = 0;
  437. int nStartingOffset = nOffset;
  438. do
  439. {
  440. int nPeekAmount = 128;
  441. // NOTE: Add 1 for the terminating zero!
  442. if ( !CheckArbitraryPeekGet( nOffset, nPeekAmount ) )
  443. {
  444. if ( nOffset == nStartingOffset )
  445. return 0;
  446. return nOffset - nStartingOffset + 1;
  447. }
  448. const char *pTest = (const char *)PeekGet( nOffset );
  449. for ( int i = 0; i < nPeekAmount; ++i )
  450. {
  451. // The +2 here is so we eat the terminating '\n' and 0
  452. if ( pTest[i] == '\n' || pTest[i] == '\r' )
  453. return (i + nOffset - nStartingOffset + 2);
  454. // The +1 here is so we eat the terminating 0
  455. if ( pTest[i] == 0 )
  456. return (i + nOffset - nStartingOffset + 1);
  457. }
  458. nOffset += nPeekAmount;
  459. } while ( true );
  460. }
  461. //-----------------------------------------------------------------------------
  462. // Does the next bytes of the buffer match a pattern?
  463. //-----------------------------------------------------------------------------
  464. bool CUtlBuffer::PeekStringMatch( int nOffset, const char *pString, int nLen )
  465. {
  466. if ( !CheckPeekGet( nOffset, nLen ) )
  467. return false;
  468. return !Q_strncmp( (const char*)PeekGet(nOffset), pString, nLen );
  469. }
  470. //-----------------------------------------------------------------------------
  471. // This version of PeekStringLength converts \" to \\ and " to \, etc.
  472. // It also reads a " at the beginning and end of the string
  473. //-----------------------------------------------------------------------------
  474. int CUtlBuffer::PeekDelimitedStringLength( CUtlCharConversion *pConv, bool bActualSize )
  475. {
  476. if ( !IsText() || !pConv )
  477. return PeekStringLength();
  478. // Eat preceeding whitespace
  479. int nOffset = 0;
  480. if ( IsText() )
  481. {
  482. nOffset = PeekWhiteSpace( nOffset );
  483. }
  484. if ( !PeekStringMatch( nOffset, pConv->GetDelimiter(), pConv->GetDelimiterLength() ) )
  485. return 0;
  486. // Try to read ending ", but don't accept \"
  487. int nActualStart = nOffset;
  488. nOffset += pConv->GetDelimiterLength();
  489. int nLen = 1; // Starts at 1 for the '\0' termination
  490. do
  491. {
  492. if ( PeekStringMatch( nOffset, pConv->GetDelimiter(), pConv->GetDelimiterLength() ) )
  493. break;
  494. if ( !CheckPeekGet( nOffset, 1 ) )
  495. break;
  496. char c = *(const char*)PeekGet( nOffset );
  497. ++nLen;
  498. ++nOffset;
  499. if ( c == pConv->GetEscapeChar() )
  500. {
  501. int nLength = pConv->MaxConversionLength();
  502. if ( !CheckArbitraryPeekGet( nOffset, nLength ) )
  503. break;
  504. pConv->FindConversion( (const char*)PeekGet(nOffset), &nLength );
  505. nOffset += nLength;
  506. }
  507. } while (true);
  508. return bActualSize ? nLen : nOffset - nActualStart + pConv->GetDelimiterLength() + 1;
  509. }
  510. //-----------------------------------------------------------------------------
  511. // Reads a null-terminated string
  512. //-----------------------------------------------------------------------------
  513. void CUtlBuffer::GetStringInternal( char *pString, size_t maxLenInChars )
  514. {
  515. if ( !IsValid() )
  516. {
  517. *pString = 0;
  518. return;
  519. }
  520. // This can legitimately be zero if we were told that the buffer is zero length, and
  521. // we're asking to duplicate the buffer, so let that pass, too.
  522. Assert( maxLenInChars != 0 || PeekStringLength() == 0 );
  523. if ( maxLenInChars == 0 )
  524. {
  525. return;
  526. }
  527. // Remember, this *includes* the null character
  528. // It will be 0, however, if the buffer is empty.
  529. int nLen = PeekStringLength();
  530. if ( IsText() )
  531. {
  532. EatWhiteSpace();
  533. }
  534. if ( nLen <= 0 )
  535. {
  536. *pString = 0;
  537. m_Error |= GET_OVERFLOW;
  538. return;
  539. }
  540. const size_t nCharsToRead = min( (size_t)nLen, maxLenInChars ) - 1;
  541. Get( pString, nCharsToRead );
  542. pString[nCharsToRead] = 0;
  543. if ( (size_t)nLen > (nCharsToRead + 1) )
  544. {
  545. SeekGet( SEEK_CURRENT, nLen - (nCharsToRead + 1) );
  546. }
  547. // Read the terminating NULL in binary formats
  548. if ( !IsText() )
  549. {
  550. VerifyEquals( GetChar(), 0 );
  551. }
  552. }
  553. //-----------------------------------------------------------------------------
  554. // Reads up to and including the first \n
  555. //-----------------------------------------------------------------------------
  556. void CUtlBuffer::GetLine( char* pLine, int nMaxChars )
  557. {
  558. Assert( IsText() && !ContainsCRLF() );
  559. if ( !IsValid() )
  560. {
  561. *pLine = 0;
  562. return;
  563. }
  564. if ( nMaxChars == 0 )
  565. {
  566. nMaxChars = INT_MAX;
  567. }
  568. // Remember, this *includes* the null character
  569. // It will be 0, however, if the buffer is empty.
  570. int nLen = PeekLineLength();
  571. if ( nLen == 0 )
  572. {
  573. *pLine = 0;
  574. m_Error |= GET_OVERFLOW;
  575. return;
  576. }
  577. // Strip off the terminating NULL
  578. if ( nLen <= nMaxChars )
  579. {
  580. Get( pLine, nLen - 1 );
  581. pLine[ nLen - 1 ] = 0;
  582. }
  583. else
  584. {
  585. Get( pLine, nMaxChars - 1 );
  586. pLine[ nMaxChars - 1 ] = 0;
  587. SeekGet( SEEK_CURRENT, nLen - 1 - nMaxChars );
  588. }
  589. }
  590. //-----------------------------------------------------------------------------
  591. // This version of GetString converts \ to \\ and " to \", etc.
  592. // It also places " at the beginning and end of the string
  593. //-----------------------------------------------------------------------------
  594. char CUtlBuffer::GetDelimitedCharInternal( CUtlCharConversion *pConv )
  595. {
  596. char c = GetChar();
  597. if ( c == pConv->GetEscapeChar() )
  598. {
  599. int nLength = pConv->MaxConversionLength();
  600. if ( !CheckArbitraryPeekGet( 0, nLength ) )
  601. return '\0';
  602. c = pConv->FindConversion( (const char *)PeekGet(), &nLength );
  603. SeekGet( SEEK_CURRENT, nLength );
  604. }
  605. return c;
  606. }
  607. char CUtlBuffer::GetDelimitedChar( CUtlCharConversion *pConv )
  608. {
  609. if ( !IsText() || !pConv )
  610. return GetChar( );
  611. return GetDelimitedCharInternal( pConv );
  612. }
  613. void CUtlBuffer::GetDelimitedString( CUtlCharConversion *pConv, char *pString, int nMaxChars )
  614. {
  615. if ( !IsText() || !pConv )
  616. {
  617. GetStringInternal( pString, nMaxChars );
  618. return;
  619. }
  620. if (!IsValid())
  621. {
  622. *pString = 0;
  623. return;
  624. }
  625. if ( nMaxChars == 0 )
  626. {
  627. nMaxChars = INT_MAX;
  628. }
  629. EatWhiteSpace();
  630. if ( !PeekStringMatch( 0, pConv->GetDelimiter(), pConv->GetDelimiterLength() ) )
  631. return;
  632. // Pull off the starting delimiter
  633. SeekGet( SEEK_CURRENT, pConv->GetDelimiterLength() );
  634. int nRead = 0;
  635. while ( IsValid() )
  636. {
  637. if ( PeekStringMatch( 0, pConv->GetDelimiter(), pConv->GetDelimiterLength() ) )
  638. {
  639. SeekGet( SEEK_CURRENT, pConv->GetDelimiterLength() );
  640. break;
  641. }
  642. char c = GetDelimitedCharInternal( pConv );
  643. if ( nRead < nMaxChars )
  644. {
  645. pString[nRead] = c;
  646. ++nRead;
  647. }
  648. }
  649. if ( nRead >= nMaxChars )
  650. {
  651. nRead = nMaxChars - 1;
  652. }
  653. pString[nRead] = '\0';
  654. }
  655. //-----------------------------------------------------------------------------
  656. // Checks if a get is ok
  657. //-----------------------------------------------------------------------------
  658. bool CUtlBuffer::CheckGet( int nSize )
  659. {
  660. if ( m_Error & GET_OVERFLOW )
  661. return false;
  662. if ( TellMaxPut() < m_Get + nSize )
  663. {
  664. m_Error |= GET_OVERFLOW;
  665. return false;
  666. }
  667. if ( ( m_Get < m_nOffset ) || ( m_Memory.NumAllocated() < m_Get - m_nOffset + nSize ) )
  668. {
  669. if ( !OnGetOverflow( nSize ) )
  670. {
  671. m_Error |= GET_OVERFLOW;
  672. return false;
  673. }
  674. }
  675. return true;
  676. }
  677. //-----------------------------------------------------------------------------
  678. // Checks if a peek get is ok
  679. //-----------------------------------------------------------------------------
  680. bool CUtlBuffer::CheckPeekGet( int nOffset, int nSize )
  681. {
  682. if ( m_Error & GET_OVERFLOW )
  683. return false;
  684. // Checking for peek can't set the overflow flag
  685. bool bOk = CheckGet( nOffset + nSize );
  686. m_Error &= ~GET_OVERFLOW;
  687. return bOk;
  688. }
  689. //-----------------------------------------------------------------------------
  690. // Call this to peek arbitrarily long into memory. It doesn't fail unless
  691. // it can't read *anything* new
  692. //-----------------------------------------------------------------------------
  693. bool CUtlBuffer::CheckArbitraryPeekGet( int nOffset, int &nIncrement )
  694. {
  695. if ( TellGet() + nOffset >= TellMaxPut() )
  696. {
  697. nIncrement = 0;
  698. return false;
  699. }
  700. if ( TellGet() + nOffset + nIncrement > TellMaxPut() )
  701. {
  702. nIncrement = TellMaxPut() - TellGet() - nOffset;
  703. }
  704. // NOTE: CheckPeekGet could modify TellMaxPut for streaming files
  705. // We have to call TellMaxPut again here
  706. CheckPeekGet( nOffset, nIncrement );
  707. int nMaxGet = TellMaxPut() - TellGet();
  708. if ( nMaxGet < nIncrement )
  709. {
  710. nIncrement = nMaxGet;
  711. }
  712. return (nIncrement != 0);
  713. }
  714. //-----------------------------------------------------------------------------
  715. // Peek part of the butt
  716. //-----------------------------------------------------------------------------
  717. const void* CUtlBuffer::PeekGet( int nMaxSize, int nOffset )
  718. {
  719. if ( !CheckPeekGet( nOffset, nMaxSize ) )
  720. return NULL;
  721. int Index = m_Get + nOffset - m_nOffset;
  722. Assert( m_Memory.IsIdxValid( Index ) && m_Memory.IsIdxValid( Index + nMaxSize - 1 ) );
  723. return &m_Memory[ Index ];
  724. }
  725. //-----------------------------------------------------------------------------
  726. // Change where I'm reading
  727. //-----------------------------------------------------------------------------
  728. void CUtlBuffer::SeekGet( SeekType_t type, int offset )
  729. {
  730. switch( type )
  731. {
  732. case SEEK_HEAD:
  733. m_Get = offset;
  734. break;
  735. case SEEK_CURRENT:
  736. m_Get += offset;
  737. break;
  738. case SEEK_TAIL:
  739. m_Get = m_nMaxPut - offset;
  740. break;
  741. }
  742. if ( m_Get > m_nMaxPut )
  743. {
  744. m_Error |= GET_OVERFLOW;
  745. }
  746. else
  747. {
  748. m_Error &= ~GET_OVERFLOW;
  749. if ( m_Get < m_nOffset || m_Get >= m_nOffset + Size() )
  750. {
  751. OnGetOverflow( -1 );
  752. }
  753. }
  754. }
  755. //-----------------------------------------------------------------------------
  756. // Parse...
  757. //-----------------------------------------------------------------------------
  758. #pragma warning ( disable : 4706 )
  759. int CUtlBuffer::VaScanf( const char* pFmt, va_list list )
  760. {
  761. Assert( pFmt );
  762. if ( m_Error || !IsText() )
  763. return 0;
  764. int numScanned = 0;
  765. int nLength;
  766. char c;
  767. char* pEnd;
  768. while ( (c = *pFmt++) )
  769. {
  770. // Stop if we hit the end of the buffer
  771. if ( m_Get >= TellMaxPut() )
  772. {
  773. m_Error |= GET_OVERFLOW;
  774. break;
  775. }
  776. switch (c)
  777. {
  778. case ' ':
  779. // eat all whitespace
  780. EatWhiteSpace();
  781. break;
  782. case '%':
  783. {
  784. // Conversion character... try to convert baby!
  785. char type = *pFmt++;
  786. if (type == 0)
  787. return numScanned;
  788. switch(type)
  789. {
  790. case 'c':
  791. {
  792. char* ch = va_arg( list, char * );
  793. if ( CheckPeekGet( 0, sizeof(char) ) )
  794. {
  795. *ch = *(const char*)PeekGet();
  796. ++m_Get;
  797. }
  798. else
  799. {
  800. *ch = 0;
  801. return numScanned;
  802. }
  803. }
  804. break;
  805. case 'i':
  806. case 'd':
  807. {
  808. int* i = va_arg( list, int * );
  809. // NOTE: This is not bullet-proof; it assumes numbers are < 128 characters
  810. nLength = 128;
  811. if ( !CheckArbitraryPeekGet( 0, nLength ) )
  812. {
  813. *i = 0;
  814. return numScanned;
  815. }
  816. *i = strtol( (char*)PeekGet(), &pEnd, 10 );
  817. int nBytesRead = (int)( pEnd - (char*)PeekGet() );
  818. if ( nBytesRead == 0 )
  819. return numScanned;
  820. m_Get += nBytesRead;
  821. }
  822. break;
  823. case 'x':
  824. {
  825. int* i = va_arg( list, int * );
  826. // NOTE: This is not bullet-proof; it assumes numbers are < 128 characters
  827. nLength = 128;
  828. if ( !CheckArbitraryPeekGet( 0, nLength ) )
  829. {
  830. *i = 0;
  831. return numScanned;
  832. }
  833. *i = strtol( (char*)PeekGet(), &pEnd, 16 );
  834. int nBytesRead = (int)( pEnd - (char*)PeekGet() );
  835. if ( nBytesRead == 0 )
  836. return numScanned;
  837. m_Get += nBytesRead;
  838. }
  839. break;
  840. case 'u':
  841. {
  842. unsigned int* u = va_arg( list, unsigned int *);
  843. // NOTE: This is not bullet-proof; it assumes numbers are < 128 characters
  844. nLength = 128;
  845. if ( !CheckArbitraryPeekGet( 0, nLength ) )
  846. {
  847. *u = 0;
  848. return numScanned;
  849. }
  850. *u = strtoul( (char*)PeekGet(), &pEnd, 10 );
  851. int nBytesRead = (int)( pEnd - (char*)PeekGet() );
  852. if ( nBytesRead == 0 )
  853. return numScanned;
  854. m_Get += nBytesRead;
  855. }
  856. break;
  857. case 'f':
  858. {
  859. float* f = va_arg( list, float *);
  860. // NOTE: This is not bullet-proof; it assumes numbers are < 128 characters
  861. nLength = 128;
  862. if ( !CheckArbitraryPeekGet( 0, nLength ) )
  863. {
  864. *f = 0.0f;
  865. return numScanned;
  866. }
  867. *f = (float)strtod( (char*)PeekGet(), &pEnd );
  868. int nBytesRead = (int)( pEnd - (char*)PeekGet() );
  869. if ( nBytesRead == 0 )
  870. return numScanned;
  871. m_Get += nBytesRead;
  872. }
  873. break;
  874. case 's':
  875. {
  876. char* s = va_arg( list, char * );
  877. GetStringInternal( s, 256 );
  878. }
  879. break;
  880. default:
  881. {
  882. // unimplemented scanf type
  883. Assert(0);
  884. return numScanned;
  885. }
  886. break;
  887. }
  888. ++numScanned;
  889. }
  890. break;
  891. default:
  892. {
  893. // Here we have to match the format string character
  894. // against what's in the buffer or we're done.
  895. if ( !CheckPeekGet( 0, sizeof(char) ) )
  896. return numScanned;
  897. if ( c != *(const char*)PeekGet() )
  898. return numScanned;
  899. ++m_Get;
  900. }
  901. }
  902. }
  903. return numScanned;
  904. }
  905. #pragma warning ( default : 4706 )
  906. int CUtlBuffer::Scanf( const char* pFmt, ... )
  907. {
  908. va_list args;
  909. va_start( args, pFmt );
  910. int count = VaScanf( pFmt, args );
  911. va_end( args );
  912. return count;
  913. }
  914. //-----------------------------------------------------------------------------
  915. // Advance the get index until after the particular string is found
  916. // Do not eat whitespace before starting. Return false if it failed
  917. //-----------------------------------------------------------------------------
  918. bool CUtlBuffer::GetToken( const char *pToken )
  919. {
  920. Assert( pToken );
  921. // Look for the token
  922. int nLen = Q_strlen( pToken );
  923. int nSizeToCheck = Size() - TellGet() - m_nOffset;
  924. int nGet = TellGet();
  925. do
  926. {
  927. int nMaxSize = TellMaxPut() - TellGet();
  928. if ( nMaxSize < nSizeToCheck )
  929. {
  930. nSizeToCheck = nMaxSize;
  931. }
  932. if ( nLen > nSizeToCheck )
  933. break;
  934. if ( !CheckPeekGet( 0, nSizeToCheck ) )
  935. break;
  936. const char *pBufStart = (const char*)PeekGet();
  937. const char *pFoundEnd = Q_strnistr( pBufStart, pToken, nSizeToCheck );
  938. if ( pFoundEnd )
  939. {
  940. size_t nOffset = (size_t)pFoundEnd - (size_t)pBufStart;
  941. SeekGet( CUtlBuffer::SEEK_CURRENT, nOffset + nLen );
  942. return true;
  943. }
  944. SeekGet( CUtlBuffer::SEEK_CURRENT, nSizeToCheck - nLen - 1 );
  945. nSizeToCheck = Size() - (nLen-1);
  946. } while ( true );
  947. SeekGet( CUtlBuffer::SEEK_HEAD, nGet );
  948. return false;
  949. }
  950. //-----------------------------------------------------------------------------
  951. // (For text buffers only)
  952. // Parse a token from the buffer:
  953. // Grab all text that lies between a starting delimiter + ending delimiter
  954. // (skipping whitespace that leads + trails both delimiters).
  955. // Note the delimiter checks are case-insensitive.
  956. // If successful, the get index is advanced and the function returns true,
  957. // otherwise the index is not advanced and the function returns false.
  958. //-----------------------------------------------------------------------------
  959. bool CUtlBuffer::ParseToken( const char *pStartingDelim, const char *pEndingDelim, char* pString, int nMaxLen )
  960. {
  961. int nCharsToCopy = 0;
  962. int nCurrentGet = 0;
  963. size_t nEndingDelimLen;
  964. // Starting delimiter is optional
  965. char emptyBuf = '\0';
  966. if ( !pStartingDelim )
  967. {
  968. pStartingDelim = &emptyBuf;
  969. }
  970. // Ending delimiter is not
  971. Assert( pEndingDelim && pEndingDelim[0] );
  972. nEndingDelimLen = Q_strlen( pEndingDelim );
  973. int nStartGet = TellGet();
  974. char nCurrChar;
  975. int nTokenStart = -1;
  976. EatWhiteSpace( );
  977. while ( *pStartingDelim )
  978. {
  979. nCurrChar = *pStartingDelim++;
  980. if ( !isspace((unsigned char)nCurrChar) )
  981. {
  982. if ( tolower( GetChar() ) != tolower( nCurrChar ) )
  983. goto parseFailed;
  984. }
  985. else
  986. {
  987. EatWhiteSpace();
  988. }
  989. }
  990. EatWhiteSpace();
  991. nTokenStart = TellGet();
  992. if ( !GetToken( pEndingDelim ) )
  993. goto parseFailed;
  994. nCurrentGet = TellGet();
  995. nCharsToCopy = (nCurrentGet - nEndingDelimLen) - nTokenStart;
  996. if ( nCharsToCopy >= nMaxLen )
  997. {
  998. nCharsToCopy = nMaxLen - 1;
  999. }
  1000. if ( nCharsToCopy > 0 )
  1001. {
  1002. SeekGet( CUtlBuffer::SEEK_HEAD, nTokenStart );
  1003. Get( pString, nCharsToCopy );
  1004. if ( !IsValid() )
  1005. goto parseFailed;
  1006. // Eat trailing whitespace
  1007. for ( ; nCharsToCopy > 0; --nCharsToCopy )
  1008. {
  1009. if ( !isspace( (unsigned char)pString[ nCharsToCopy-1 ] ) )
  1010. break;
  1011. }
  1012. }
  1013. pString[ nCharsToCopy ] = '\0';
  1014. // Advance the Get index
  1015. SeekGet( CUtlBuffer::SEEK_HEAD, nCurrentGet );
  1016. return true;
  1017. parseFailed:
  1018. // Revert the get index
  1019. SeekGet( SEEK_HEAD, nStartGet );
  1020. pString[0] = '\0';
  1021. return false;
  1022. }
  1023. //-----------------------------------------------------------------------------
  1024. // Parses the next token, given a set of character breaks to stop at
  1025. //-----------------------------------------------------------------------------
  1026. int CUtlBuffer::ParseToken( characterset_t *pBreaks, char *pTokenBuf, int nMaxLen, bool bParseComments )
  1027. {
  1028. Assert( nMaxLen > 0 );
  1029. pTokenBuf[0] = 0;
  1030. // skip whitespace + comments
  1031. while ( true )
  1032. {
  1033. if ( !IsValid() )
  1034. return -1;
  1035. EatWhiteSpace();
  1036. if ( bParseComments )
  1037. {
  1038. if ( !EatCPPComment() )
  1039. break;
  1040. }
  1041. else
  1042. {
  1043. break;
  1044. }
  1045. }
  1046. char c = GetChar();
  1047. // End of buffer
  1048. if ( c == 0 )
  1049. return -1;
  1050. // handle quoted strings specially
  1051. if ( c == '\"' )
  1052. {
  1053. int nLen = 0;
  1054. while( IsValid() )
  1055. {
  1056. c = GetChar();
  1057. if ( c == '\"' || !c )
  1058. {
  1059. pTokenBuf[nLen] = 0;
  1060. return nLen;
  1061. }
  1062. pTokenBuf[nLen] = c;
  1063. if ( ++nLen == nMaxLen )
  1064. {
  1065. pTokenBuf[nLen-1] = 0;
  1066. return nMaxLen;
  1067. }
  1068. }
  1069. // In this case, we hit the end of the buffer before hitting the end qoute
  1070. pTokenBuf[nLen] = 0;
  1071. return nLen;
  1072. }
  1073. // parse single characters
  1074. if ( IN_CHARACTERSET( *pBreaks, c ) )
  1075. {
  1076. pTokenBuf[0] = c;
  1077. pTokenBuf[1] = 0;
  1078. return 1;
  1079. }
  1080. // parse a regular word
  1081. int nLen = 0;
  1082. while ( true )
  1083. {
  1084. pTokenBuf[nLen] = c;
  1085. if ( ++nLen == nMaxLen )
  1086. {
  1087. pTokenBuf[nLen-1] = 0;
  1088. return nMaxLen;
  1089. }
  1090. c = GetChar();
  1091. if ( !IsValid() )
  1092. break;
  1093. if ( IN_CHARACTERSET( *pBreaks, c ) || c == '\"' || c <= ' ' )
  1094. {
  1095. SeekGet( SEEK_CURRENT, -1 );
  1096. break;
  1097. }
  1098. }
  1099. pTokenBuf[nLen] = 0;
  1100. return nLen;
  1101. }
  1102. //-----------------------------------------------------------------------------
  1103. // Serialization
  1104. //-----------------------------------------------------------------------------
  1105. void CUtlBuffer::Put( const void *pMem, int size )
  1106. {
  1107. if ( size && CheckPut( size ) )
  1108. {
  1109. int Index = m_Put - m_nOffset;
  1110. Assert( m_Memory.IsIdxValid( Index ) && m_Memory.IsIdxValid( Index + size - 1 ) );
  1111. if( Index >= 0 )
  1112. {
  1113. memcpy( &m_Memory[ Index ], pMem, size );
  1114. m_Put += size;
  1115. AddNullTermination();
  1116. }
  1117. }
  1118. }
  1119. //-----------------------------------------------------------------------------
  1120. // Writes a null-terminated string
  1121. //-----------------------------------------------------------------------------
  1122. void CUtlBuffer::PutString( const char* pString )
  1123. {
  1124. if (!IsText())
  1125. {
  1126. if ( pString )
  1127. {
  1128. // Not text? append a null at the end.
  1129. size_t nLen = Q_strlen( pString ) + 1;
  1130. Put( pString, nLen * sizeof(char) );
  1131. return;
  1132. }
  1133. else
  1134. {
  1135. PutTypeBin<char>( 0 );
  1136. }
  1137. }
  1138. else if (pString)
  1139. {
  1140. int nTabCount = ( m_Flags & AUTO_TABS_DISABLED ) ? 0 : m_nTab;
  1141. if ( nTabCount > 0 )
  1142. {
  1143. if ( WasLastCharacterCR() )
  1144. {
  1145. PutTabs();
  1146. }
  1147. const char* pEndl = strchr( pString, '\n' );
  1148. while ( pEndl )
  1149. {
  1150. size_t nSize = (size_t)pEndl - (size_t)pString + sizeof(char);
  1151. Put( pString, nSize );
  1152. pString = pEndl + 1;
  1153. if ( *pString )
  1154. {
  1155. PutTabs();
  1156. pEndl = strchr( pString, '\n' );
  1157. }
  1158. else
  1159. {
  1160. pEndl = NULL;
  1161. }
  1162. }
  1163. }
  1164. size_t nLen = Q_strlen( pString );
  1165. if ( nLen )
  1166. {
  1167. Put( pString, nLen * sizeof(char) );
  1168. }
  1169. }
  1170. }
  1171. //-----------------------------------------------------------------------------
  1172. // This version of PutString converts \ to \\ and " to \", etc.
  1173. // It also places " at the beginning and end of the string
  1174. //-----------------------------------------------------------------------------
  1175. inline void CUtlBuffer::PutDelimitedCharInternal( CUtlCharConversion *pConv, char c )
  1176. {
  1177. int l = pConv->GetConversionLength( c );
  1178. if ( l == 0 )
  1179. {
  1180. PutChar( c );
  1181. }
  1182. else
  1183. {
  1184. PutChar( pConv->GetEscapeChar() );
  1185. Put( pConv->GetConversionString( c ), l );
  1186. }
  1187. }
  1188. void CUtlBuffer::PutDelimitedChar( CUtlCharConversion *pConv, char c )
  1189. {
  1190. if ( !IsText() || !pConv )
  1191. {
  1192. PutChar( c );
  1193. return;
  1194. }
  1195. PutDelimitedCharInternal( pConv, c );
  1196. }
  1197. void CUtlBuffer::PutDelimitedString( CUtlCharConversion *pConv, const char *pString )
  1198. {
  1199. if ( !IsText() || !pConv )
  1200. {
  1201. PutString( pString );
  1202. return;
  1203. }
  1204. if ( WasLastCharacterCR() )
  1205. {
  1206. PutTabs();
  1207. }
  1208. Put( pConv->GetDelimiter(), pConv->GetDelimiterLength() );
  1209. int nLen = pString ? Q_strlen( pString ) : 0;
  1210. for ( int i = 0; i < nLen; ++i )
  1211. {
  1212. PutDelimitedCharInternal( pConv, pString[i] );
  1213. }
  1214. if ( WasLastCharacterCR() )
  1215. {
  1216. PutTabs();
  1217. }
  1218. Put( pConv->GetDelimiter(), pConv->GetDelimiterLength() );
  1219. }
  1220. void CUtlBuffer::VaPrintf( const char* pFmt, va_list list )
  1221. {
  1222. char temp[2048];
  1223. #ifdef DBGFLAG_ASSERT
  1224. int nLen =
  1225. #endif
  1226. Q_vsnprintf( temp, sizeof( temp ), pFmt, list );
  1227. Assert( nLen < 2048 );
  1228. PutString( temp );
  1229. }
  1230. void CUtlBuffer::Printf( const char* pFmt, ... )
  1231. {
  1232. va_list args;
  1233. va_start( args, pFmt );
  1234. VaPrintf( pFmt, args );
  1235. va_end( args );
  1236. }
  1237. //-----------------------------------------------------------------------------
  1238. // Calls the overflow functions
  1239. //-----------------------------------------------------------------------------
  1240. void CUtlBuffer::SetOverflowFuncs( UtlBufferOverflowFunc_t getFunc, UtlBufferOverflowFunc_t putFunc )
  1241. {
  1242. m_GetOverflowFunc = getFunc;
  1243. m_PutOverflowFunc = putFunc;
  1244. }
  1245. //-----------------------------------------------------------------------------
  1246. // Calls the overflow functions
  1247. //-----------------------------------------------------------------------------
  1248. bool CUtlBuffer::OnPutOverflow( int nSize )
  1249. {
  1250. return (this->*m_PutOverflowFunc)( nSize );
  1251. }
  1252. bool CUtlBuffer::OnGetOverflow( int nSize )
  1253. {
  1254. return (this->*m_GetOverflowFunc)( nSize );
  1255. }
  1256. //-----------------------------------------------------------------------------
  1257. // Checks if a put is ok
  1258. //-----------------------------------------------------------------------------
  1259. bool CUtlBuffer::PutOverflow( int nSize )
  1260. {
  1261. MEM_ALLOC_CREDIT();
  1262. if ( m_Memory.IsExternallyAllocated() )
  1263. {
  1264. if ( !IsGrowable() )
  1265. return false;
  1266. m_Memory.ConvertToGrowableMemory( 0 );
  1267. }
  1268. while( Size() < m_Put - m_nOffset + nSize )
  1269. {
  1270. m_Memory.Grow();
  1271. }
  1272. return true;
  1273. }
  1274. bool CUtlBuffer::GetOverflow( int nSize )
  1275. {
  1276. return false;
  1277. }
  1278. //-----------------------------------------------------------------------------
  1279. // Checks if a put is ok
  1280. //-----------------------------------------------------------------------------
  1281. bool CUtlBuffer::CheckPut( int nSize )
  1282. {
  1283. if ( ( m_Error & PUT_OVERFLOW ) || IsReadOnly() )
  1284. return false;
  1285. if ( ( m_Put < m_nOffset ) || ( m_Memory.NumAllocated() < m_Put - m_nOffset + nSize ) )
  1286. {
  1287. if ( !OnPutOverflow( nSize ) )
  1288. {
  1289. m_Error |= PUT_OVERFLOW;
  1290. return false;
  1291. }
  1292. }
  1293. return true;
  1294. }
  1295. void CUtlBuffer::SeekPut( SeekType_t type, int offset )
  1296. {
  1297. int nNextPut = m_Put;
  1298. switch( type )
  1299. {
  1300. case SEEK_HEAD:
  1301. nNextPut = offset;
  1302. break;
  1303. case SEEK_CURRENT:
  1304. nNextPut += offset;
  1305. break;
  1306. case SEEK_TAIL:
  1307. nNextPut = m_nMaxPut - offset;
  1308. break;
  1309. }
  1310. // Force a write of the data
  1311. // FIXME: We could make this more optimal potentially by writing out
  1312. // the entire buffer if you seek outside the current range
  1313. // NOTE: This call will write and will also seek the file to nNextPut.
  1314. OnPutOverflow( -nNextPut-1 );
  1315. m_Put = nNextPut;
  1316. AddNullTermination();
  1317. }
  1318. void CUtlBuffer::ActivateByteSwapping( bool bActivate )
  1319. {
  1320. m_Byteswap.ActivateByteSwapping( bActivate );
  1321. }
  1322. void CUtlBuffer::SetBigEndian( bool bigEndian )
  1323. {
  1324. m_Byteswap.SetTargetBigEndian( bigEndian );
  1325. }
  1326. bool CUtlBuffer::IsBigEndian( void )
  1327. {
  1328. return m_Byteswap.IsTargetBigEndian();
  1329. }
  1330. //-----------------------------------------------------------------------------
  1331. // null terminate the buffer
  1332. //-----------------------------------------------------------------------------
  1333. void CUtlBuffer::AddNullTermination( void )
  1334. {
  1335. if ( m_Put > m_nMaxPut )
  1336. {
  1337. if ( !IsReadOnly() && ((m_Error & PUT_OVERFLOW) == 0) )
  1338. {
  1339. // Add null termination value
  1340. if ( CheckPut( 1 ) )
  1341. {
  1342. int Index = m_Put - m_nOffset;
  1343. Assert( m_Memory.IsIdxValid( Index ) );
  1344. if( Index >= 0 )
  1345. {
  1346. m_Memory[ Index ] = 0;
  1347. }
  1348. }
  1349. else
  1350. {
  1351. // Restore the overflow state, it was valid before...
  1352. m_Error &= ~PUT_OVERFLOW;
  1353. }
  1354. }
  1355. m_nMaxPut = m_Put;
  1356. }
  1357. }
  1358. //-----------------------------------------------------------------------------
  1359. // Converts a buffer from a CRLF buffer to a CR buffer (and back)
  1360. // Returns false if no conversion was necessary (and outBuf is left untouched)
  1361. // If the conversion occurs, outBuf will be cleared.
  1362. //-----------------------------------------------------------------------------
  1363. bool CUtlBuffer::ConvertCRLF( CUtlBuffer &outBuf )
  1364. {
  1365. if ( !IsText() || !outBuf.IsText() )
  1366. return false;
  1367. if ( ContainsCRLF() == outBuf.ContainsCRLF() )
  1368. return false;
  1369. int nInCount = TellMaxPut();
  1370. outBuf.Purge();
  1371. outBuf.EnsureCapacity( nInCount );
  1372. bool bFromCRLF = ContainsCRLF();
  1373. // Start reading from the beginning
  1374. int nGet = TellGet();
  1375. int nPut = TellPut();
  1376. int nGetDelta = 0;
  1377. int nPutDelta = 0;
  1378. const char *pBase = (const char*)Base();
  1379. int nCurrGet = 0;
  1380. while ( nCurrGet < nInCount )
  1381. {
  1382. const char *pCurr = &pBase[nCurrGet];
  1383. if ( bFromCRLF )
  1384. {
  1385. const char *pNext = Q_strnistr( pCurr, "\r\n", nInCount - nCurrGet );
  1386. if ( !pNext )
  1387. {
  1388. outBuf.Put( pCurr, nInCount - nCurrGet );
  1389. break;
  1390. }
  1391. int nBytes = (size_t)pNext - (size_t)pCurr;
  1392. outBuf.Put( pCurr, nBytes );
  1393. outBuf.PutChar( '\n' );
  1394. nCurrGet += nBytes + 2;
  1395. if ( nGet >= nCurrGet - 1 )
  1396. {
  1397. --nGetDelta;
  1398. }
  1399. if ( nPut >= nCurrGet - 1 )
  1400. {
  1401. --nPutDelta;
  1402. }
  1403. }
  1404. else
  1405. {
  1406. const char *pNext = Q_strnchr( pCurr, '\n', nInCount - nCurrGet );
  1407. if ( !pNext )
  1408. {
  1409. outBuf.Put( pCurr, nInCount - nCurrGet );
  1410. break;
  1411. }
  1412. int nBytes = (size_t)pNext - (size_t)pCurr;
  1413. outBuf.Put( pCurr, nBytes );
  1414. outBuf.PutChar( '\r' );
  1415. outBuf.PutChar( '\n' );
  1416. nCurrGet += nBytes + 1;
  1417. if ( nGet >= nCurrGet )
  1418. {
  1419. ++nGetDelta;
  1420. }
  1421. if ( nPut >= nCurrGet )
  1422. {
  1423. ++nPutDelta;
  1424. }
  1425. }
  1426. }
  1427. Assert( nPut + nPutDelta <= outBuf.TellMaxPut() );
  1428. outBuf.SeekGet( SEEK_HEAD, nGet + nGetDelta );
  1429. outBuf.SeekPut( SEEK_HEAD, nPut + nPutDelta );
  1430. return true;
  1431. }
  1432. //-----------------------------------------------------------------------------
  1433. // Fast swap
  1434. //-----------------------------------------------------------------------------
  1435. void CUtlBuffer::Swap( CUtlBuffer &buf )
  1436. {
  1437. V_swap( m_Get, buf.m_Get );
  1438. V_swap( m_Put, buf.m_Put );
  1439. V_swap( m_nMaxPut, buf.m_nMaxPut );
  1440. V_swap( m_Error, buf.m_Error );
  1441. m_Memory.Swap( buf.m_Memory );
  1442. }
  1443. //-----------------------------------------------------------------------------
  1444. // Fast swap w/ a CUtlMemory.
  1445. //-----------------------------------------------------------------------------
  1446. void CUtlBuffer::Swap( CUtlMemory<uint8> &mem )
  1447. {
  1448. m_Get = 0;
  1449. m_Put = mem.Count();
  1450. m_nMaxPut = mem.Count();
  1451. m_Error = 0;
  1452. m_Memory.Swap( mem );
  1453. }
  1454. //---------------------------------------------------------------------------
  1455. // Implementation of CUtlInplaceBuffer
  1456. //---------------------------------------------------------------------------
  1457. CUtlInplaceBuffer::CUtlInplaceBuffer( int growSize /* = 0 */, int initSize /* = 0 */, int nFlags /* = 0 */ ) :
  1458. CUtlBuffer( growSize, initSize, nFlags )
  1459. {
  1460. }
  1461. bool CUtlInplaceBuffer::InplaceGetLinePtr( char **ppszInBufferPtr, int *pnLineLength )
  1462. {
  1463. Assert( IsText() && !ContainsCRLF() );
  1464. int nLineLen = PeekLineLength();
  1465. if ( nLineLen <= 1 )
  1466. {
  1467. SeekGet( SEEK_TAIL, 0 );
  1468. return false;
  1469. }
  1470. -- nLineLen; // because it accounts for putting a terminating null-character
  1471. char *pszLine = ( char * ) const_cast< void * >( PeekGet() );
  1472. SeekGet( SEEK_CURRENT, nLineLen );
  1473. // Set the out args
  1474. if ( ppszInBufferPtr )
  1475. *ppszInBufferPtr = pszLine;
  1476. if ( pnLineLength )
  1477. *pnLineLength = nLineLen;
  1478. return true;
  1479. }
  1480. char * CUtlInplaceBuffer::InplaceGetLinePtr( void )
  1481. {
  1482. char *pszLine = NULL;
  1483. int nLineLen = 0;
  1484. if ( InplaceGetLinePtr( &pszLine, &nLineLen ) )
  1485. {
  1486. Assert( nLineLen >= 1 );
  1487. switch ( pszLine[ nLineLen - 1 ] )
  1488. {
  1489. case '\n':
  1490. case '\r':
  1491. pszLine[ nLineLen - 1 ] = 0;
  1492. if ( -- nLineLen )
  1493. {
  1494. switch ( pszLine[ nLineLen - 1 ] )
  1495. {
  1496. case '\n':
  1497. case '\r':
  1498. pszLine[ nLineLen - 1 ] = 0;
  1499. break;
  1500. }
  1501. }
  1502. break;
  1503. default:
  1504. Assert( pszLine[ nLineLen ] == 0 );
  1505. break;
  1506. }
  1507. }
  1508. return pszLine;
  1509. }