bool CUtlInplaceBuffer::InplaceGetLinePtr( char **ppszInBufferPtr, int *pnLineLength ) { Assert( IsText() && !ContainsCRLF() ); int nLineLen = PeekLineLength(); if ( nLineLen <= 1 ) { SeekGet( SEEK_TAIL, 0 ); return false; } -- nLineLen; // because it accounts for putting a terminating null-character char *pszLine = ( char * ) const_cast< void * >( PeekGet() ); SeekGet( SEEK_CURRENT, nLineLen ); // Set the out args if ( ppszInBufferPtr ) *ppszInBufferPtr = pszLine; if ( pnLineLength ) *pnLineLength = nLineLen; return true; }
//----------------------------------------------------------------------------- // This version of PeekStringLength converts \" to \\ and " to \, etc. // It also reads a " at the beginning and end of the string //----------------------------------------------------------------------------- int CUtlBufferEditor::PeekDelimitedStringLength( CUtlCharConversion *pConv, bool bActualSize ) { if ( !IsText() || !pConv ) return PeekStringLength(); // Eat preceeding whitespace int nOffset = 0; if ( IsText() ) { nOffset = PeekWhiteSpace( nOffset ); } if ( !PeekStringMatch( nOffset, pConv->GetDelimiter(), pConv->GetDelimiterLength() ) ) return 0; // Try to read ending ", but don't accept \" int nActualStart = nOffset; nOffset += pConv->GetDelimiterLength(); int nLen = 1; // Starts at 1 for the '\0' termination do { if ( PeekStringMatch( nOffset, pConv->GetDelimiter(), pConv->GetDelimiterLength() ) ) break; if ( !CheckPeekGet( nOffset, 1 ) ) break; char c = *(const char*)PeekGet( nOffset ); ++nLen; ++nOffset; if ( c == pConv->GetEscapeChar() ) { int nLength = pConv->MaxConversionLength(); if ( !CheckArbitraryPeekGet( nOffset, nLength ) ) break; pConv->FindConversion( (const char*)PeekGet(nOffset), &nLength ); nOffset += nLength; } } while (true); return bActualSize ? nLen : nOffset - nActualStart + pConv->GetDelimiterLength() + 1; }
//----------------------------------------------------------------------------- // Eats whitespace //----------------------------------------------------------------------------- void CUtlBufferEditor::EatWhiteSpace() { if ( IsText() && IsValid() ) { while ( CheckGet( sizeof(char) ) ) { if ( !isspace( *(const unsigned char*)PeekGet() ) ) break; m_Get += sizeof(char); } } }
//----------------------------------------------------------------------------- // Peek size of sting to come, check memory bound //----------------------------------------------------------------------------- int CUtlBufferEditor::PeekStringLength() { if ( !IsValid() ) return 0; // Eat preceeding whitespace int nOffset = 0; if ( IsText() ) { nOffset = PeekWhiteSpace( nOffset ); } int nStartingOffset = nOffset; do { int nPeekAmount = 128; // NOTE: Add 1 for the terminating zero! if ( !CheckArbitraryPeekGet( nOffset, nPeekAmount ) ) { if ( nOffset == nStartingOffset ) return 0; return nOffset - nStartingOffset + 1; } const char *pTest = (const char *)PeekGet( nOffset ); if ( !IsText() ) { for ( int i = 0; i < nPeekAmount; ++i ) { // The +1 here is so we eat the terminating 0 if ( pTest[i] == 0 ) return (i + nOffset - nStartingOffset + 1); } } else { for ( int i = 0; i < nPeekAmount; ++i ) { // The +1 here is so we eat the terminating 0 if ( isspace((unsigned char)pTest[i]) || (pTest[i] == 0) ) return (i + nOffset - nStartingOffset + 1); } } nOffset += nPeekAmount; } while ( true ); }
//----------------------------------------------------------------------------- // Peeks how much whitespace to eat //----------------------------------------------------------------------------- int CUtlBufferEditor::PeekWhiteSpace( int nOffset ) { if ( !IsText() || !IsValid() ) return 0; while ( CheckPeekGet( nOffset, sizeof(char) ) ) { if ( !isspace( *(unsigned char*)PeekGet( nOffset ) ) ) break; nOffset += sizeof(char); } return nOffset; }
//----------------------------------------------------------------------------- // This version of GetString converts \ to \\ and " to \", etc. // It also places " at the beginning and end of the string //----------------------------------------------------------------------------- char CUtlBufferEditor::GetDelimitedCharInternal( CUtlCharConversion *pConv ) { char c = GetChar(); if ( c == pConv->GetEscapeChar() ) { int nLength = pConv->MaxConversionLength(); if ( !CheckArbitraryPeekGet( 0, nLength ) ) return '\0'; c = pConv->FindConversion( (const char *)PeekGet(), &nLength ); SeekGet( SEEK_CURRENT, nLength ); } return c; }
//----------------------------------------------------------------------------- // Advance the get index until after the particular string is found // Do not eat whitespace before starting. Return false if it failed //----------------------------------------------------------------------------- bool CUtlBufferEditor::GetToken( const char *pToken ) { Assert( pToken ); // Look for the token int nLen = Q_strlen( pToken ); int nSizeToCheck = Size() - TellGet() - m_nOffset; int nGet = TellGet(); do { int nMaxSize = TellMaxPut() - TellGet(); if ( nMaxSize < nSizeToCheck ) { nSizeToCheck = nMaxSize; } if ( nLen > nSizeToCheck ) break; if ( !CheckPeekGet( 0, nSizeToCheck ) ) break; const char *pBufStart = (const char*)PeekGet(); const char *pFoundEnd = Q_strnistr( pBufStart, pToken, nSizeToCheck ); if ( pFoundEnd ) { size_t nOffset = (size_t)pFoundEnd - (size_t)pBufStart; SeekGet( CUtlBufferEditor::SEEK_CURRENT, nOffset + nLen ); return true; } SeekGet( CUtlBufferEditor::SEEK_CURRENT, nSizeToCheck - nLen - 1 ); nSizeToCheck = Size() - (nLen-1); } while ( true ); SeekGet( CUtlBufferEditor::SEEK_HEAD, nGet ); return false; }
//----------------------------------------------------------------------------- // Eats C++ style comments //----------------------------------------------------------------------------- bool CUtlBufferEditor::EatCPPComment() { if ( IsText() && IsValid() ) { // If we don't have a a c++ style comment next, we're done const char *pPeek = (const char *)PeekGet( 2 * sizeof(char), 0 ); if ( !pPeek || ( pPeek[0] != '/' ) || ( pPeek[1] != '/' ) ) return false; // Deal with c++ style comments m_Get += 2; // read complete line for ( char c = GetChar(); IsValid(); c = GetChar() ) { if ( c == '\n' ) break; } return true; } return false; }
//----------------------------------------------------------------------------- // Peek size of line to come, check memory bound //----------------------------------------------------------------------------- int CUtlBufferEditor::PeekLineLength() { if ( !IsValid() ) return 0; int nOffset = 0; int nStartingOffset = nOffset; do { int nPeekAmount = 128; // NOTE: Add 1 for the terminating zero! if ( !CheckArbitraryPeekGet( nOffset, nPeekAmount ) ) { if ( nOffset == nStartingOffset ) return 0; return nOffset - nStartingOffset + 1; } const char *pTest = (const char *)PeekGet( nOffset ); for ( int i = 0; i < nPeekAmount; ++i ) { // The +2 here is so we eat the terminating '\n' and 0 if ( pTest[i] == '\n' || pTest[i] == '\r' ) return (i + nOffset - nStartingOffset + 2); // The +1 here is so we eat the terminating 0 if ( pTest[i] == 0 ) return (i + nOffset - nStartingOffset + 1); } nOffset += nPeekAmount; } while ( true ); }
int CUtlBufferEditor::VaScanf( const char* pFmt, va_list list ) { Assert( pFmt ); if ( m_Error || !IsText() ) return 0; int numScanned = 0; int nLength; char c; char* pEnd; while ( c = *pFmt++ ) { // Stop if we hit the end of the buffer if ( m_Get >= TellMaxPut() ) { m_Error |= GET_OVERFLOW; break; } switch (c) { case ' ': // eat all whitespace EatWhiteSpace(); break; case '%': { // Conversion character... try to convert baby! char type = *pFmt++; if (type == 0) return numScanned; switch(type) { case 'c': { char* ch = va_arg( list, char * ); if ( CheckPeekGet( 0, sizeof(char) ) ) { *ch = *(const char*)PeekGet(); ++m_Get; } else { *ch = 0; return numScanned; } } break; case 'i': case 'd': { int* i = va_arg( list, int * ); // NOTE: This is not bullet-proof; it assumes numbers are < 128 characters nLength = 128; if ( !CheckArbitraryPeekGet( 0, nLength ) ) { *i = 0; return numScanned; } *i = strtol( (char*)PeekGet(), &pEnd, 10 ); int nBytesRead = (int)( pEnd - (char*)PeekGet() ); if ( nBytesRead == 0 ) return numScanned; m_Get += nBytesRead; } break; case 'x': { int* i = va_arg( list, int * ); // NOTE: This is not bullet-proof; it assumes numbers are < 128 characters nLength = 128; if ( !CheckArbitraryPeekGet( 0, nLength ) ) { *i = 0; return numScanned; } *i = strtol( (char*)PeekGet(), &pEnd, 16 ); int nBytesRead = (int)( pEnd - (char*)PeekGet() ); if ( nBytesRead == 0 ) return numScanned; m_Get += nBytesRead; } break; case 'u': { unsigned int* u = va_arg( list, unsigned int *); // NOTE: This is not bullet-proof; it assumes numbers are < 128 characters nLength = 128; if ( !CheckArbitraryPeekGet( 0, nLength ) ) { *u = 0; return numScanned; } *u = strtoul( (char*)PeekGet(), &pEnd, 10 ); int nBytesRead = (int)( pEnd - (char*)PeekGet() ); if ( nBytesRead == 0 ) return numScanned; m_Get += nBytesRead; } break; case 'f': { float* f = va_arg( list, float *); // NOTE: This is not bullet-proof; it assumes numbers are < 128 characters nLength = 128; if ( !CheckArbitraryPeekGet( 0, nLength ) ) { *f = 0.0f; return numScanned; } *f = (float)strtod( (char*)PeekGet(), &pEnd ); int nBytesRead = (int)( pEnd - (char*)PeekGet() ); if ( nBytesRead == 0 ) return numScanned; m_Get += nBytesRead; } break; case 's': { char* s = va_arg( list, char * ); GetString( s ); } break; default: { // unimplemented scanf type Assert(0); return numScanned; } break; } ++numScanned; } break; default: { // Here we have to match the format string character // against what's in the buffer or we're done. if ( !CheckPeekGet( 0, sizeof(char) ) ) return numScanned; if ( c != *(const char*)PeekGet() ) return numScanned; ++m_Get; } } } return numScanned; }
//----------------------------------------------------------------------------- // Does the next bytes of the buffer match a pattern? //----------------------------------------------------------------------------- bool CUtlBufferEditor::PeekStringMatch( int nOffset, const char *pString, int nLen ) { if ( !CheckPeekGet( nOffset, nLen ) ) return false; return !Q_strncmp( (const char*)PeekGet(nOffset), pString, nLen ); }