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.

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