//----------------------------------------------------------------------------- // Peeks how much whitespace to eat //----------------------------------------------------------------------------- int CUtlBuffer::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 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; }
//----------------------------------------------------------------------------- // 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; }
//----------------------------------------------------------------------------- // Call this to peek arbitrarily long into memory. It doesn't fail unless // it can't read *anything* new //----------------------------------------------------------------------------- bool CUtlBufferEditor::CheckArbitraryPeekGet( int nOffset, int &nIncrement ) { if ( TellGet() + nOffset >= TellMaxPut() ) { nIncrement = 0; return false; } if ( TellGet() + nOffset + nIncrement > TellMaxPut() ) { nIncrement = TellMaxPut() - TellGet() - nOffset; } // NOTE: CheckPeekGet could modify TellMaxPut for streaming files // We have to call TellMaxPut again here CheckPeekGet( nOffset, nIncrement ); int nMaxGet = TellMaxPut() - TellGet(); if ( nMaxGet < nIncrement ) { nIncrement = nMaxGet; } return (nIncrement != 0); }
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; }
//----------------------------------------------------------------------------- // Peek part of the butt //----------------------------------------------------------------------------- const void* CUtlBufferEditor::PeekGet( int nMaxSize, int nOffset ) { if ( !CheckPeekGet( nOffset, nMaxSize ) ) return NULL; return &m_Memory[ m_Get + nOffset - m_nOffset ]; }
//----------------------------------------------------------------------------- // 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 ); }