1 //====== Copyright 1996-2005, Valve Corporation, All rights reserved. =======//
2 //
3 // Purpose:
4 //
5 // $NoKeywords: $
6 //
7 // Serialization/unserialization buffer
8 //=============================================================================//
9 
10 #ifndef UTLBUFFER_H
11 #define UTLBUFFER_H
12 
13 #ifdef _WIN32
14 #pragma once
15 #endif
16 
17 #include "tier1/utlmemory.h"
18 #include <stdarg.h>
19 //SDR_PUBLIC #include "tier1/utlstring.h"
20 
21 //-----------------------------------------------------------------------------
22 // Description of character conversions for string output
23 // Here's an example of how to use the macros to define a character conversion
24 // BEGIN_CHAR_CONVERSION( CStringConversion, '\\' )
25 //	{ '\n', "n" },
26 //	{ '\t', "t" }
27 // END_CHAR_CONVERSION( CStringConversion, '\\' )
28 //-----------------------------------------------------------------------------
29 class CUtlCharConversion
30 {
31 public:
32 	struct ConversionArray_t
33 	{
34 		char m_nActualChar;
35 		const char *m_pReplacementString;
36 	};
37 
38 	CUtlCharConversion( const char nEscapeChar, const char *pDelimiter, int nCount, ConversionArray_t *pArray );
39 	char GetEscapeChar() const;
40 	const char *GetDelimiter() const;
41 	int GetDelimiterLength() const;
42 
43 	const char *GetConversionString( char c ) const;
44 	int GetConversionLength( char c ) const;
45 	int MaxConversionLength() const;
46 
47 	// Finds a conversion for the passed-in string, returns length
48 	virtual char FindConversion( const char *pString, int *pLength );
49 
50 protected:
51 	struct ConversionInfo_t
52 	{
53 		int m_nLength;
54 		const char *m_pReplacementString;
55 	};
56 
57 	char m_nEscapeChar;
58 	const char *m_pDelimiter;
59 	int m_nDelimiterLength;
60 	int m_nCount;
61 	int m_nMaxConversionLength;
62 	char m_pList[255];
63 	ConversionInfo_t m_pReplacements[255];
64 };
65 
66 #define BEGIN_CHAR_CONVERSION( _name, _delimiter, _escapeChar )	\
67 	static CUtlCharConversion::ConversionArray_t s_pConversionArray ## _name[] = {
68 
69 #define END_CHAR_CONVERSION( _name, _delimiter, _escapeChar ) \
70 	}; \
71 	CUtlCharConversion _name( _escapeChar, _delimiter, sizeof( s_pConversionArray ## _name ) / sizeof( CUtlCharConversion::ConversionArray_t ), s_pConversionArray ## _name );
72 
73 #define BEGIN_CUSTOM_CHAR_CONVERSION( _className, _name, _delimiter, _escapeChar ) \
74 	static CUtlCharConversion::ConversionArray_t s_pConversionArray ## _name[] = {
75 
76 #define END_CUSTOM_CHAR_CONVERSION( _className, _name, _delimiter, _escapeChar ) \
77 	}; \
78 	_className _name( _escapeChar, _delimiter, sizeof( s_pConversionArray ## _name ) / sizeof( CUtlCharConversion::ConversionArray_t ), s_pConversionArray ## _name );
79 
80 //-----------------------------------------------------------------------------
81 // Character conversions for C strings
82 //-----------------------------------------------------------------------------
83 CUtlCharConversion *GetCStringCharConversion();
84 
85 //-----------------------------------------------------------------------------
86 // Character conversions for quoted strings, with no escape sequences
87 //-----------------------------------------------------------------------------
88 CUtlCharConversion *GetNoEscCharConversion();
89 
90 
91 //-----------------------------------------------------------------------------
92 // Macro to set overflow functions easily
93 //-----------------------------------------------------------------------------
94 #define SetUtlBufferOverflowFuncs( _get, _put )	\
95 	SetOverflowFuncs( static_cast <UtlBufferOverflowFunc_t>( _get ), static_cast <UtlBufferOverflowFunc_t>( _put ) )
96 
97 
98 //-----------------------------------------------------------------------------
99 // Command parsing..
100 //-----------------------------------------------------------------------------
101 class CUtlBuffer
102 {
103 public:
104 	enum SeekType_t
105 	{
106 		SEEK_HEAD = 0,
107 		SEEK_CURRENT,
108 		SEEK_TAIL
109 	};
110 
111 	// flags
112 	enum BufferFlags_t
113 	{
114 		TEXT_BUFFER = 0x1,			// Describes how get + put work (as strings, or binary)
115 		EXTERNAL_GROWABLE = 0x2,	// This is used w/ external buffers and causes the utlbuf to switch to reallocatable memory if an overflow happens when Putting.
116 		CONTAINS_CRLF = 0x4,		// For text buffers only, does this contain \n or \n\r?
117 		READ_ONLY = 0x8,			// For external buffers; prevents null termination from happening.
118 		AUTO_TABS_DISABLED = 0x10,	// Used to disable/enable push/pop tabs
119 		LITTLE_ENDIAN_BUFFER = 0x20,// ensures that data is stored in little endian format
120 		BIG_ENDIAN_BUFFER = 0x40,	// ensures that data is stored in big endian format
121 	};
122 
123 	// Overflow functions when a get or put overflows
124 	typedef bool (CUtlBuffer::*UtlBufferOverflowFunc_t)( int nSize );
125 
126 	// Constructors for growable + external buffers for serialization/unserialization
127 	CUtlBuffer( int growSize = 0, int initSize = 0, int nFlags = 0 );
128 	CUtlBuffer( const void* pBuffer, int size, int nFlags = 0 );
129 
130 	unsigned char	GetFlags() const;
131 
132 	// NOTE: This will assert if you attempt to recast it in a way that
133 	// is not compatible. The only valid conversion is binary-> text w/CRLF
134 	void			SetBufferType( bool bIsText, bool bContainsCRLF );
135 
136 	// Makes sure we've got at least this much memory
137 	void			EnsureCapacity( int num );
138 
139 	// Attaches the buffer to external memory....
140 	void			SetExternalBuffer( void* pMemory, int nSize, int nInitialPut, int nFlags = 0 );
141 
142 	// Attaches to an external buffer as read only. Will purge any existing buffer data
143 	void			SetReadOnlyBuffer( void *pMemory, int nSize );
144 
145 	// Controls endian-ness of binary utlbufs
146 	// Resets the buffer; but doesn't free memory
147 	void			Clear();
148 
149 	// Clears out the buffer; frees memory
150 	void			Purge();
151 
152 	void			Swap( CUtlBuffer &buf );
153 	void			TakeOwnershipOfMemory( CUtlMemory<uint8> &mem );
154 	void			ReleaseToMemory( CUtlMemory<uint8> &mem, int *punCurrentPut );
155 
156 	// detaches the memory, returns it, and clears the members (but detached memory is preserved)
157 	void *			DetachAndClear();
158 
159 	// copies data from another buffer
160 	void			CopyBuffer( const CUtlBuffer &buffer );
161 	void			CopyBuffer( const void *pubData, int cubData );
162 
163 
164 	// Read stuff out.
165 	// Binary mode: it'll just read the bits directly in, and characters will be
166 	//		read for strings until a null character is reached.
167 	// Text mode: it'll parse the file, turning text #s into real numbers.
168 	//		GetString will read a string until a space is reached
169 
170 	char			GetChar();
171 	uint8			GetUint8();
172 	short			GetShort();
173 	unsigned short	GetUnsignedShort();
174 	int				GetInt();
175 	int				GetIntHex();
176 	unsigned int	GetUnsignedInt();
177 	int16			GetInt16();
178 	uint64			GetUnsignedInt64();
179 	int64			GetInt64();
180 	float			GetFloat();
181 	double			GetDouble();
182 	bool			GetString( char *pString, int nMaxLen );
183 	bool			GetLine( char *pString, int nMaxLen );
184 	const char*		GetStringFast(); // binary mode only
185 	bool			Get( void* pMem, int size );
186 
187 	// This will get at least 1 byte and up to nSize bytes.
188 	// It will return the number of bytes actually read.
189 	int				GetUpTo( void *pMem, int nSize );
190 
191 	// This version of GetString converts \" to \\ and " to \, etc.
192 	// It also reads a " at the beginning and end of the string
193 	void			GetDelimitedString( CUtlCharConversion *pConv, char *pString, int nMaxChars );
194 	char			GetDelimitedChar( CUtlCharConversion *pConv );
195 
196 	// This will return the # of characters of the string about to be read out
197 	// NOTE: The count will *include* the terminating 0!!
198 	// In binary mode, it's the number of characters until the next 0
199 	// In text mode, it's the number of characters until the next space.
200 	int				PeekStringLength();
201 
202 	// This version of PeekStringLength converts \" to \\ and " to \, etc.
203 	// It also reads a " at the beginning and end of the string
204 	// NOTE: The count will *include* the terminating 0!!
205 	// In binary mode, it's the number of characters until the next 0
206 	// In text mode, it's the number of characters between "s (checking for \")
207 	// Specifying false for bActualSize will return the pre-translated number of characters
208 	// including the delimiters and the escape characters. So, \n counts as 2 characters when bActualSize == false
209 	// and only 1 character when bActualSize == true
210 	int				PeekDelimitedStringLength( CUtlCharConversion *pConv, bool bActualSize = true );
211 
212 	// Just like scanf, but doesn't work in binary mode
213 	int				Scanf( SCANF_FORMAT_STRING const char* pFmt, ... );
214 	int				VaScanf( const char* pFmt, va_list list );
215 
216 	// Eats white space, advances Get index
217 	void			EatWhiteSpace();
218 	// Eats white space, advances Get index - won't overflow if file ends with whitespace.
219 	void			EatWhiteSpaceNoOverflow();
220 
221 	// Eats C++ style comments
222 	bool			EatCPPComment();
223 
224 	// (For text buffers only)
225 	// Parse a token from the buffer:
226 	// Grab all text that lies between a starting delimiter + ending delimiter
227 	// (skipping whitespace that leads + trails both delimiters).
228 	// If successful, the get index is advanced and the function returns true,
229 	// otherwise the index is not advanced and the function returns false.
230 	bool			ParseToken( const char *pStartingDelim, const char *pEndingDelim, char* pString, int nMaxLen );
231 
232 	// Advance the get index until after the particular string is found
233 	// Do not eat whitespace before starting. Return false if it failed
234 	// String test is case-insensitive.
235 	bool			GetToken( const char *pToken );
236 
237 	// Write stuff in
238 	// Binary mode: it'll just write the bits directly in, and strings will be
239 	//		written with a null terminating character
240 	// Text mode: it'll convert the numbers to text versions
241 	//		PutString will not write a terminating character
242 	void			PutChar( char c );
243 	void			PutUint8( uint8 ub );
244 	void			PutShort( short s );
245 	void			PutUnsignedShort( unsigned short us );
246 	void			PutInt( int i );
247 	void			PutUnsignedInt( unsigned int u );
248 	void			PutInt16( int16 s16 );
249 	void			PutUnsignedInt64( uint64 u64 );
250 	void			PutInt64( int64 u64 );
251 	void			PutFloat( float f );
252 	void			PutDouble( double d );
253 	void			PutString( const char* pString );
254 	void			PutStringWithoutNull( const char* pString );
255 	void			Put( const void* pMem, int size );
256 
257 	// This version of PutString converts \ to \\ and " to \", etc.
258 	// It also places " at the beginning and end of the string
259 	void			PutDelimitedString( CUtlCharConversion *pConv, const char *pString );
260 	void			PutDelimitedChar( CUtlCharConversion *pConv, char c );
261 
262 	// Just like printf, writes a terminating zero in binary mode
263 	void			Printf( PRINTF_FORMAT_STRING const char* pFmt, ... ) FMTFUNCTION( 2, 3 );
264 	void			VaPrintf( const char* pFmt, va_list list );
265 
266 	// What am I writing (put)/reading (get)?
267 	void* PeekPut( int offset = 0 );
268 	const void* PeekGet( ) const;
269 	const void* PeekGet( int offset ) const;
270 	const void* PeekGet( int nMaxSize, int nOffset );
271 
272 	// Reserve at least nBytes and return the pointer to the start of the reserved area.
273 	// Like EnsureCapacity(TellPut()+nBytes) but non-exact; preserves geometric growth.
274 	void *ReservePut( int nBytes );
275 
276 	// How many bytes remain to be read?
277 	// NOTE: This is not accurate for streaming text files; it overshoots
278 	int GetBytesRemaining() const;
279 
280 	// Where am I writing (put)/reading (get)?
281 	int  TellPut() const;
282 	int  TellGet() const;
283 
284 	// Change where I'm writing (put)/reading (get)
285 	void SeekPut( SeekType_t type, int offset );
286 	bool SeekGet( SeekType_t type, int offset );
287 
288 	// Buffer base
289 	const void* Base() const;
290 	void* Base();
291 	// Returns the base as a const char*, only valid in text mode.
292 	const char *String() const;
293 	// Copies the content of the buffer into a string (valid for binary and text mode).
294 	//SDR_PUBLIC void CopyToString( CUtlString &strText ) const;
295 
296 	// memory allocation size, does *not* reflect size written or read,
297 	//	use TellPut or TellGet for that
298 	int Size() const; // FIXME will delete soon
299 	int SizeAllocated() const;
300 
301 	// Am I a text buffer?
302 	bool IsText() const;
303 
304 	// Am I externally allocated (may not be growable, check below)
305 	bool IsExternallyAllocated() const;
306 
307 	// Can I grow if I'm externally allocated?
308 	bool IsGrowable() const;
309 
310 	// Am I valid? (overflow or underflow error), Once invalid it stays invalid
311 	bool IsValid() const;
312 
313 	// Do I contain carriage return/linefeeds?
314 	bool ContainsCRLF() const;
315 
316 	// Am I read-only
317 	bool IsReadOnly() const;
318 
319 	// Converts a buffer from a CRLF buffer to a CR buffer (and back)
320 	// Returns false if no conversion was necessary (and outBuf is left untouched)
321 	// If the conversion occurs, outBuf will be cleared.
322 	bool ConvertCRLF( CUtlBuffer &outBuf );
323 
324 	// Push/pop pretty-printing tabs
325 	void PushTab();
326 	void PopTab();
327 
328 	// Temporarily disables pretty print
329 	void EnableTabs( bool bEnable );
330 
331 	// Securely erases buffer
SecureZero()332 	void SecureZero() { SecureZeroMemory( m_Memory.Base(), m_Memory.Count() ); }
333 
334 protected:
335 	// error flags
336 	enum
337 	{
338 		PUT_OVERFLOW = 0x1,
339 		GET_OVERFLOW = 0x2,
340 		MAX_ERROR_FLAG = GET_OVERFLOW,
341 	};
342 
343 	void SetOverflowFuncs( UtlBufferOverflowFunc_t getFunc, UtlBufferOverflowFunc_t putFunc );
344 
345 	bool OnPutOverflow( int nSize );
346 	bool OnGetOverflow( int nSize );
347 
348 protected:
349 	// Checks if a get/put is ok
350 	bool CheckPut( int size );
351 	bool CheckGet( int size );
352 
353 	void AddNullTermination( );
354 
355 	// Methods to help with pretty-printing
356 	bool WasLastCharacterCR();
357 	void PutTabs();
358 
359 	// Help with delimited stuff
360 	char GetDelimitedCharInternal( CUtlCharConversion *pConv );
361 	void PutDelimitedCharInternal( CUtlCharConversion *pConv, char c );
362 
363 	// Default overflow funcs
364 	bool PutOverflow( int nSize );
365 	bool GetOverflow( int nSize );
366 
367 	// Does the next bytes of the buffer match a pattern?
368 	bool PeekStringMatch( int nOffset, const char *pString, int nLen );
369 
370 	// How much whitespace should I skip?
371 	int PeekWhiteSpace( int nOffset );
372 
373 	// Checks if a peek get is ok
374 	bool CheckPeekGet( int nOffset, int nSize );
375 
376 	// Call this to peek arbitrarily long into memory. It doesn't fail unless
377 	// it can't read *anything* new
378 	bool CheckArbitraryPeekGet( int nOffset, int &nIncrement );
379 
380 	CUtlMemory<uint8> m_Memory;
381 	int m_Get;
382 	int m_Put;
383 
384 	int m_nMaxPut;
385 	uint16 m_nTab;
386 
387 	uint8 m_Error;
388 	uint8 m_Flags;
389 
390 	UtlBufferOverflowFunc_t m_GetOverflowFunc;
391 	UtlBufferOverflowFunc_t m_PutOverflowFunc;
392 
393 private:
394 	// Returns max amount of data written. Used internally but externally you should use put / seek
395 	int TellMaxPut() const;
396 
397 	// Copy construction and assignment are not valid
398 	CUtlBuffer(const CUtlBuffer& rhs);
399 	const CUtlBuffer& operator=(const CUtlBuffer& rhs);
400 };
401 
402 
403 //-----------------------------------------------------------------------------
404 // Where am I reading?
405 //-----------------------------------------------------------------------------
TellGet()406 inline int CUtlBuffer::TellGet() const
407 {
408 	return m_Get;
409 }
410 
411 
412 //-----------------------------------------------------------------------------
413 // How many bytes remain to be read?
414 //-----------------------------------------------------------------------------
GetBytesRemaining()415 inline int CUtlBuffer::GetBytesRemaining() const
416 {
417 	return m_nMaxPut - TellGet();
418 }
419 
420 
421 //-----------------------------------------------------------------------------
422 // What am I reading?
423 //-----------------------------------------------------------------------------
PeekGet(int offset)424 inline const void* CUtlBuffer::PeekGet( int offset ) const
425 {
426 	return &m_Memory[ m_Get + offset ];
427 }
428 
429 //-----------------------------------------------------------------------------
430 // no offset so optimizer can resolve the function
431 //-----------------------------------------------------------------------------
PeekGet()432 inline const void* CUtlBuffer::PeekGet() const
433 {
434 	return &m_Memory[ m_Get ];
435 }
436 
437 //-----------------------------------------------------------------------------
438 // Reserve nBytes at the put location and return pointer; follow with SeekPut
439 //-----------------------------------------------------------------------------
ReservePut(int nBytes)440 inline void *CUtlBuffer::ReservePut( int nBytes )
441 {
442 	return CheckPut( nBytes ) ? PeekPut() : NULL;
443 }
444 
445 //-----------------------------------------------------------------------------
446 // Unserialization
447 //-----------------------------------------------------------------------------
448 #if defined(__arm__) || defined(__arm64__)
449 #define COPY_TYPE( _type, _val ) V_memcpy( &_val, PeekGet(), sizeof( _type ) )
450 #else
451 #define COPY_TYPE( _type, _val ) _val = *(_type *)PeekGet()
452 #endif
453 #define GET_TYPE( _type, _val, _fmt )			\
454 	if ( !IsText() )							\
455 	{											\
456 		if (CheckGet( sizeof(_type) ))			\
457 		{										\
458 			if ( (sizeof(_type)>1) && (m_Flags & CUtlBuffer::LITTLE_ENDIAN_BUFFER ) )	\
459 			{									\
460 				if( sizeof(_type) == 2 )		\
461 				{								\
462 					_val = LittleWord( (uint16)*(_type *)PeekGet() ); \
463 				}								\
464 				else if ( sizeof(_type) == 4 )	\
465 				{								\
466 					_val = LittleDWord( (uint32)*(_type *)PeekGet() ); \
467 				}								\
468 				else if ( sizeof(_type) == 8 )	\
469 				{								\
470 					_val = LittleQWord( (uint64)*(_type *)PeekGet() );	\
471 				}								\
472 				else							\
473 				{								\
474 					Assert( !"Type not supported" ); \
475 				}								\
476 			}									\
477 			else if ( (sizeof(_type)>1) && (m_Flags & CUtlBuffer::BIG_ENDIAN_BUFFER ) )	\
478 			{									\
479 				if( sizeof(_type) == 2 )		\
480 				{								\
481 					_val = BigWord( (uint16)*(_type *)PeekGet() ); \
482 				}								\
483 				else if ( sizeof(_type) == 4 )	\
484 				{								\
485 					_val = BigDWord( (uint32)*(_type *)PeekGet() ); \
486 				}								\
487 				else if ( sizeof(_type) == 8 )	\
488 				{								\
489 					_val = BigQWord( (uint64)*(_type *)PeekGet() );	\
490 				}								\
491 				else							\
492 				{								\
493 					Assert( !"Type not supported" ); \
494 				}								\
495 			}									\
496 			else								\
497 			{									\
498 				COPY_TYPE( _type, _val );		\
499 			}									\
500 			m_Get += sizeof(_type);				\
501 		}										\
502 		else									\
503 		{										\
504 			_val = 0;							\
505 		}										\
506 	}											\
507 	else										\
508 	{											\
509 		_val = 0;								\
510 		Scanf( _fmt, &_val );					\
511 	}
512 
513 
514 //-----------------------------------------------------------------------------
515 // Where am I writing?
516 //-----------------------------------------------------------------------------
GetFlags()517 inline unsigned char CUtlBuffer::GetFlags() const
518 {
519 	return m_Flags;
520 }
521 
522 
523 //-----------------------------------------------------------------------------
524 // Where am I writing?
525 //-----------------------------------------------------------------------------
TellPut()526 inline int CUtlBuffer::TellPut() const
527 {
528 	return m_Put;
529 }
530 
531 
532 //-----------------------------------------------------------------------------
533 // What's the most I've ever written?
534 //-----------------------------------------------------------------------------
TellMaxPut()535 inline int CUtlBuffer::TellMaxPut( ) const
536 {
537 	return m_nMaxPut;
538 }
539 
540 
541 //-----------------------------------------------------------------------------
542 // What am I reading?
543 //-----------------------------------------------------------------------------
PeekPut(int offset)544 inline void* CUtlBuffer::PeekPut( int offset )
545 {
546 	return &m_Memory[m_Put + offset];
547 }
548 
549 
550 //-----------------------------------------------------------------------------
551 //-----------------------------------------------------------------------------
552 // Various put methods
553 //-----------------------------------------------------------------------------
554 #define PUT_BIN_DATA( _type, _val )		\
555 	if ( CheckPut( sizeof(_type) ) )	\
556 	{										\
557 		if ( (sizeof(_type)>1) && (m_Flags & CUtlBuffer::LITTLE_ENDIAN_BUFFER ) )	\
558 		{									\
559 			if( sizeof(_type) == 2 )		\
560 			{								\
561 				*(_type *)PeekPut() = (_type)LittleWord( (uint16)_val ); \
562 			}								\
563 			else if ( sizeof(_type) == 4 )	\
564 			{								\
565 				*(_type *)PeekPut() = (_type)LittleDWord( (uint32)_val ); \
566 			}								\
567 			else if ( sizeof(_type) == 8 )	\
568 			{								\
569 				*(_type *)PeekPut() = (_type)LittleQWord( (uint64)_val ); \
570 			}								\
571 			else							\
572 			{								\
573 				Assert( !"Type not supported" ); \
574 			}								\
575 		}									\
576 		else if ( (sizeof(_type)>1) && (m_Flags & CUtlBuffer::BIG_ENDIAN_BUFFER ) )	\
577 		{									\
578 			if( sizeof(_type) == 2 )		\
579 			{								\
580 				*(_type *)PeekPut() = (_type)BigWord( (uint16)_val );   \
581 			}								\
582 			else if ( sizeof(_type) == 4 )	\
583 			{								\
584 				*(_type *)PeekPut() = (_type)BigDWord( (uint32)_val );  \
585 			}								\
586 			else if ( sizeof(_type) == 8 )	\
587 			{								\
588 				*(_type *)PeekPut() = (_type)BigQWord( (uint64)_val );	\
589 			}								\
590 			else							\
591 			{								\
592 				Assert( !"Type not supported" ); \
593 			}								\
594 		}									\
595 		else								\
596 		{									\
597 			*(_type *)PeekPut() = _val;		\
598 		}									\
599 		m_Put += sizeof(_type);				\
600 		AddNullTermination();				\
601 	}										\
602 
603 
604 #define PUT_TYPE( _type, _val )			\
605 	if (!IsText())						\
606 	{									\
607 		PUT_BIN_DATA( _type, _val );	\
608 	}									\
609 	else								\
610 	{									\
611 		PutString( CNumStr( _val ) );	\
612 	}
613 
614 
615 //-----------------------------------------------------------------------------
616 // Methods to help with pretty-printing
617 //-----------------------------------------------------------------------------
WasLastCharacterCR()618 inline bool CUtlBuffer::WasLastCharacterCR()
619 {
620 	if ( !IsText() || (TellPut() == 0) )
621 		return false;
622 	return ( *( const char * )PeekPut( -1 ) == '\n' );
623 }
624 
PutTabs()625 inline void CUtlBuffer::PutTabs()
626 {
627 	int nTabCount = ( m_Flags & AUTO_TABS_DISABLED ) ? 0 : m_nTab;
628 	for (int i = nTabCount; --i >= 0; )
629 	{
630 		PUT_BIN_DATA( char, '\t' );
631 	}
632 }
633 
634 
635 //-----------------------------------------------------------------------------
636 // Push/pop pretty-printing tabs
637 //-----------------------------------------------------------------------------
PushTab()638 inline void CUtlBuffer::PushTab( )
639 {
640 	++m_nTab;
641 }
642 
PopTab()643 inline void CUtlBuffer::PopTab()
644 {
645 	if ( m_nTab )
646 	{
647 		m_nTab--;
648 	}
649 }
650 
651 
652 //-----------------------------------------------------------------------------
653 // Temporarily disables pretty print
654 //-----------------------------------------------------------------------------
EnableTabs(bool bEnable)655 inline void CUtlBuffer::EnableTabs( bool bEnable )
656 {
657 	if ( bEnable )
658 	{
659 		m_Flags &= ~AUTO_TABS_DISABLED;
660 	}
661 	else
662 	{
663 		m_Flags |= AUTO_TABS_DISABLED;
664 	}
665 }
666 
667 
668 //-----------------------------------------------------------------------------
669 // Am I a text buffer?
670 //-----------------------------------------------------------------------------
IsText()671 inline bool CUtlBuffer::IsText() const
672 {
673 	return (m_Flags & TEXT_BUFFER) != 0;
674 }
675 
676 
677 //-----------------------------------------------------------------------------
678 // Can I grow if I'm externally allocated?
679 //-----------------------------------------------------------------------------
IsGrowable()680 inline bool CUtlBuffer::IsGrowable() const
681 {
682 	return (m_Flags & EXTERNAL_GROWABLE) != 0;
683 }
684 
685 //-----------------------------------------------------------------------------
686 // Am I externally allocated (may need to check IsGrowable or can't grow buffer)
687 //-----------------------------------------------------------------------------
IsExternallyAllocated()688 inline bool CUtlBuffer::IsExternallyAllocated() const
689 {
690 	return m_Memory.IsExternallyAllocated();
691 }
692 
693 //-----------------------------------------------------------------------------
694 // Am I valid? (overflow or underflow error), Once invalid it stays invalid
695 //-----------------------------------------------------------------------------
IsValid()696 inline bool CUtlBuffer::IsValid() const
697 {
698 	return m_Error == 0;
699 }
700 
701 
702 //-----------------------------------------------------------------------------
703 // Do I contain carriage return/linefeeds?
704 //-----------------------------------------------------------------------------
ContainsCRLF()705 inline bool CUtlBuffer::ContainsCRLF() const
706 {
707 	return IsText() && ((m_Flags & CONTAINS_CRLF) != 0);
708 }
709 
710 
711 //-----------------------------------------------------------------------------
712 // Am I read-only
713 //-----------------------------------------------------------------------------
IsReadOnly()714 inline bool CUtlBuffer::IsReadOnly() const
715 {
716 	return (m_Flags & READ_ONLY) != 0;
717 }
718 
719 
720 //-----------------------------------------------------------------------------
721 // Buffer base and size
722 //-----------------------------------------------------------------------------
Base()723 inline const void* CUtlBuffer::Base() const
724 {
725 	return m_Memory.Base();
726 }
727 
Base()728 inline void* CUtlBuffer::Base()
729 {
730 	return m_Memory.Base();
731 }
732 
733 // Returns the base as a const char*, only valid in text mode.
String()734 inline const char *CUtlBuffer::String() const
735 {
736 	Assert( IsText() );
737 	const char *pchReturn = reinterpret_cast<const char*>( m_Memory.Base() );
738 	// Never return NULL
739 	if ( pchReturn )
740 		return pchReturn;
741 	else
742 		return "";
743 }
744 
745 //SDR_PUBLIC inline void CUtlBuffer::CopyToString( CUtlString &strText ) const
746 //SDR_PUBLIC {
747 //SDR_PUBLIC 	strText.SetDirect( (const char *)Base(), TellMaxPut() );
748 //SDR_PUBLIC }
749 
750 
Size()751 inline int CUtlBuffer::Size() const // FIXME delete soon
752 {
753 	return m_Memory.NumAllocated();
754 }
SizeAllocated()755 inline int CUtlBuffer::SizeAllocated() const
756 {
757 	return m_Memory.NumAllocated();
758 }
759 
760 
761 //-----------------------------------------------------------------------------
762 // Clears out the buffer; does not free memory
763 //-----------------------------------------------------------------------------
Clear()764 inline void CUtlBuffer::Clear()
765 {
766 	m_Get = 0;
767 	m_Put = 0;
768 	m_Error = 0;
769 	m_nMaxPut = -1;
770 	AddNullTermination();
771 }
772 
773 //-----------------------------------------------------------------------------
774 // Clears out the buffer; frees memory
775 //-----------------------------------------------------------------------------
Purge()776 inline void CUtlBuffer::Purge()
777 {
778 	m_Get = 0;
779 	m_Put = 0;
780 	m_nMaxPut = 0;
781 	m_Error = 0;
782 	m_Memory.Purge();
783 }
784 
CopyBuffer(const CUtlBuffer & buffer)785 inline void CUtlBuffer::CopyBuffer( const CUtlBuffer &buffer )
786 {
787 	CopyBuffer( buffer.Base(), buffer.TellPut() );
788 }
789 
CopyBuffer(const void * pubData,int cubData)790 inline void	CUtlBuffer::CopyBuffer( const void *pubData, int cubData )
791 {
792 	Clear();
793 	if ( cubData )
794 	{
795 		Put( pubData, cubData );
796 	}
797 }
798 
799 
800 /// CUtlBuffer that will wipe upon destruction
801 //
802 /// WARNING: This is only intended for simple use cases where the caller
803 /// can easily pre-allocate.  For example, it won't wipe if the buffer needs
804 /// to be relocated as a result of realloc.  Or if you pas it to a function
805 /// via a CUtlBuffer&, and CUtlBuffer::Purge is invoked directly.  Etc.
806 class CAutoWipeBuffer : public CUtlBuffer
807 {
808 public:
CAutoWipeBuffer()809 	CAutoWipeBuffer() {}
CAutoWipeBuffer(int cbInit)810 	explicit CAutoWipeBuffer( int cbInit ) : CUtlBuffer( 0, cbInit, 0 ) {}
~CAutoWipeBuffer()811 	~CAutoWipeBuffer() { Purge(); }
812 
Clear()813 	void Clear()
814 	{
815 		SecureZeroMemory( Base(), SizeAllocated() );
816 		CUtlBuffer::Clear();
817 	}
818 
Purge()819 	void Purge()
820 	{
821 		Clear();
822 		CUtlBuffer::Purge();
823 	}
824 };
825 
826 #endif // UTLBUFFER_H
827 
828