IIS.Common/open-inc/stbuff.h

1014 строки
19 KiB
C++

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
#ifndef _STBUFF_H
#define _STBUFF_H
#include <stdio.h>
#include <windows.h>
#define STB_INLINE_SIZE 64
#define STB_MAX_ALLOC 16*1024
#define TO_UPPER(ch) (isupper(ch) ? ch : toupper(ch))
class STBUFF
{
public:
STBUFF(
BOOL fZeroInit = TRUE
) : _pData( _Inline ),
_cbData( 0 ),
_cbBuffer( STB_INLINE_SIZE ),
_cbMaxAlloc( STB_MAX_ALLOC )
{
if ( fZeroInit )
{
ZeroInit();
}
_Inline[STB_INLINE_SIZE] = 0;
_Inline[STB_INLINE_SIZE+1] = 0;
}
virtual
~STBUFF()
{
Reset( TRUE );
}
VOID
Reset(
BOOL fFreeAlloc = FALSE
)
{
//
// If we are supposed to free any heap
// allocations, do so now.
//
if ( fFreeAlloc &&
_pData != _Inline )
{
LocalFree( _pData );
_pData = _Inline;
_cbBuffer = STB_INLINE_SIZE;
}
//
// Reset the data size
//
_cbData = 0;
}
HRESULT
Resize(
DWORD cbSize
)
{
HRESULT hr = S_OK;
BYTE * pTemp;
//
// If the buffer is large enough, just return
//
if ( cbSize < _cbBuffer )
{
goto Finished;
}
//
// If the requested size exceeds our maximum
// allocation, then fail this call.
//
if ( cbSize > _cbMaxAlloc )
{
hr = E_OUTOFMEMORY;
goto Finished;
}
//
// Adjust the allocation size so that we allocate
// in chunks of MINITOOLS_INLINE_SIZE. Don't
// exeed _cbMaxAlloc.
//
if ( cbSize % STB_INLINE_SIZE )
{
cbSize = ( cbSize / STB_INLINE_SIZE + 1 ) *
STB_INLINE_SIZE;
}
if ( cbSize > _cbMaxAlloc )
{
cbSize = _cbMaxAlloc;
}
//
// Allocate the new storage and copy any existing
// data into it.
//
// Allocate two extra bytes so that we can guarantee
// NULL termination when someone queries the data
// pointer as a string.
//
pTemp = (BYTE*)LocalAlloc( LPTR, cbSize + 2 );
if ( !pTemp )
{
hr = E_OUTOFMEMORY;
goto Finished;
}
if ( _cbData )
{
CopyMemory( pTemp, _pData, _cbData );
}
//
// If the original buffer is not the inline
// storage, then free it.
//
if ( _pData != _Inline )
{
LocalFree( _pData );
}
//
// Save the new storage pointer
//
_pData = pTemp;
_cbBuffer = cbSize;
//
// Set the extra two bytes as 0
//
_pData[_cbBuffer] = 0;
_pData[_cbBuffer+1] = 0;
Finished:
return hr;
}
HRESULT
AppendData(
VOID * pData,
DWORD cbData,
DWORD Offset = 0xffffffff
)
{
DWORD cbNeeded;
HRESULT hr = S_OK;
//
// Resize the buffer if necessary
//
cbNeeded = Offset + cbData;
hr = Resize( cbNeeded );
if ( FAILED( hr ) )
{
goto Finished;
}
//
// Copy the new data
//
if ( cbData )
{
CopyMemory( _pData + Offset, pData, cbData );
}
_cbData = cbNeeded;
//
// NULL terminate the data
//
GuaranteeNullTermination();
Finished:
return hr;
}
HRESULT
AppendData(
LPCSTR szData,
DWORD cchData = 0xffffffff,
DWORD Offset = 0xffffffff
)
{
//
// If cchData is 0xffffffff, then calculate size
//
if ( cchData == 0xffffffff )
{
cchData = (DWORD)strlen( szData );
}
//
// If offset is 0xffffffff, then assume
// that we are appending to the end of the
// string.
//
if ( Offset == 0xffffffff )
{
Offset = _cbData;
}
return AppendData( (VOID*)szData,
cchData,
Offset );
}
HRESULT
AppendData(
LPCWSTR szData,
DWORD cchData = 0xffffffff,
DWORD cchOffset = 0xffffffff
)
{
DWORD cbData;
DWORD cbOffset;
//
// If cchData is 0xffffffff, then calculate size
//
if ( cchData == 0xffffffff )
{
cchData = (DWORD)wcslen( szData );
}
cbData = cchData * sizeof(WCHAR);
//
// If offset is 0xffffffff, then assume
// that we are appending to the end of the
// string.
//
if ( cchOffset == 0xffffffff )
{
cchOffset = _cbData;
}
cbOffset = cchOffset * sizeof(WCHAR);
return AppendData( (VOID*)szData,
cbData,
cbOffset );
}
HRESULT
AppendData(
STBUFF *pbuff
)
{
return AppendData( pbuff->QueryPtr(),
pbuff->QueryDataSize() );
}
HRESULT
SetData(
VOID * pData,
DWORD cbData
)
{
//
// Set data is just an append to offset zero
//
return AppendData( pData,
cbData,
0 );
}
HRESULT
SetData(
LPCSTR pData,
DWORD cchData = 0xffffffff
)
{
//
// If cbData is 0xffffffff, then assume that
// pData is a NULL terminated string.
//
if ( cchData == 0xffffffff )
{
cchData = (DWORD)strlen( (LPSTR)pData );
}
return SetData( (VOID*)pData, cchData );
}
HRESULT
SetData(
LPCWSTR pData,
DWORD cchData = 0xffffffff
)
{
//
// If cbData is 0xffffffff, then assume that
// pData is a NULL terminated string.
//
if ( cchData == 0xffffffff )
{
cchData = (DWORD)wcslen( (LPWSTR)pData );
}
return SetData( (VOID*)pData, cchData * sizeof(WCHAR) );
}
HRESULT
SetData(
STBUFF *pbuff
)
{
return AppendData( pbuff->QueryPtr(),
pbuff->QueryDataSize(),
0 );
}
HRESULT
AnsiToUnicode(
LPCSTR szString,
UINT codepage = CP_UTF8
)
{
DWORD cchString = (DWORD)strlen( szString );
HRESULT hr = S_OK;
hr = Resize( cchString * sizeof(WCHAR) );
if ( FAILED( hr ) )
{
goto Finished;
}
if ( !MultiByteToWideChar( codepage,
MB_ERR_INVALID_CHARS,
szString,
cchString,
(LPWSTR)_pData,
cchString ) )
{
hr = HRESULT_FROM_WIN32( GetLastError() );
goto Finished;
}
_cbData = cchString * sizeof(WCHAR);
Finished:
return hr;
}
HRESULT
UnicodeToAnsi(
LPCWSTR szStringW,
UINT codepage = CP_UTF8
)
{
DWORD cchString = (DWORD)wcslen( szStringW );
HRESULT hr = S_OK;
hr = Resize( cchString );
if ( FAILED( hr ) )
{
goto Finished;
}
if ( !WideCharToMultiByte( codepage,
0,
szStringW,
cchString,
(LPSTR)_pData,
cchString,
NULL,
NULL ) )
{
hr = HRESULT_FROM_WIN32( GetLastError() );
goto Finished;
}
_cbData = cchString;
Finished:
return hr;
}
HRESULT
ExpandEnvironmentStrings(
VOID
)
{
STBUFF Temp;
DWORD cbNeeded;
HRESULT hr = S_OK;
cbNeeded = ::ExpandEnvironmentStringsA( QueryStr(),
Temp.QueryStr(),
Temp.QueryBufferSize() );
if ( cbNeeded > Temp.QueryBufferSize() )
{
hr = Temp.Resize ( cbNeeded );
if ( FAILED (hr) )
{
goto Finished;
}
cbNeeded = ::ExpandEnvironmentStringsA( QueryStr(),
Temp.QueryStr(),
Temp.QueryBufferSize() );
}
Temp.CalcDataSize();
hr = SetData( &Temp );
if ( FAILED (hr) )
{
goto Finished;
}
Finished:
return hr;
}
HRESULT
Vsprintf(
LPCSTR szFormat,
va_list args
)
{
DWORD cchWritten;
HRESULT hr = S_OK;
DWORD cbNeeded = _vscprintf( szFormat, args );
hr = Resize( cbNeeded + 1 );
if ( FAILED( hr ) )
{
goto Finished;
}
cchWritten = _vsnprintf_s( QueryStr(),
QueryBufferSize(),
QueryBufferSize(),
szFormat,
args );
_cbData = cchWritten;
Finished:
return hr;
}
HRESULT
Vsprintf(
LPCWSTR szFormat,
va_list args
)
{
DWORD cchWritten;
HRESULT hr = S_OK;
DWORD cbNeeded = _vscwprintf( szFormat, args ) * sizeof(WCHAR);
hr = Resize( cbNeeded + 1 );
if ( FAILED( hr ) )
{
goto Finished;
}
cchWritten = _vsnwprintf_s( QueryStrW(),
QueryBufferSize() / sizeof(WCHAR),
_TRUNCATE,
szFormat,
args );
_cbData = cchWritten * sizeof(WCHAR);
Finished:
return hr;
}
HRESULT
Printf(
LPCSTR szFormat,
...
)
{
HRESULT hr;
//
// Let Vsprintf do the work
//
va_list args;
va_start( args, szFormat );
hr = Vsprintf( szFormat,
args );
va_end( args );
return hr;
}
HRESULT
Printf(
LPCWSTR szFormat,
...
)
{
HRESULT hr;
//
// Let Vsprintf do the work
//
va_list args;
va_start( args, szFormat );
hr = Vsprintf( szFormat,
args );
va_end( args );
return hr;
}
VOID *
QueryPtr()
{
return (VOID*)_pData;
}
LPSTR
QueryStr()
{
GuaranteeNullTermination();
return (LPSTR)_pData;
}
LPWSTR
QueryStrW()
{
GuaranteeNullTermination();
return (LPWSTR)_pData;
}
DWORD
QueryDataSize()
{
return _cbData;
}
HRESULT
SetDataSize(
DWORD cbData
)
{
HRESULT hr = S_OK;
if ( cbData > _cbBuffer )
{
hr = HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER );
goto Finished;
}
_cbData = cbData;
Finished:
return hr;
}
VOID
CalcDataSize()
{
_cbData = (DWORD)strlen( (LPSTR)_pData );
}
VOID
CalcDataSizeW()
{
_cbData = (DWORD)wcslen( (LPWSTR)_pData );
}
DWORD
QueryBufferSize()
{
return _cbBuffer;
}
DWORD
QueryMaxAlloc()
{
return _cbMaxAlloc;
}
VOID
SetMaxAlloc(
DWORD cbMaxAlloc
)
{
_cbMaxAlloc = cbMaxAlloc;
}
VOID
ZeroInit(
VOID
)
{
FillMemory( _Inline, STB_INLINE_SIZE, 0x00 );
if ( _pData != _Inline )
{
FillMemory( _pData, _cbBuffer, 0x00 );
}
}
HRESULT
Escape(
BOOL fAllowDoubleEscaping = FALSE
)
{
STBUFF Temp;
DWORD dwNumEscapes = 0;
CHAR szHex[3] = {0};
BYTE * pRead;
BYTE * pWrite;
HRESULT hr = S_OK;
//
// Walk through the string once. If there
// are no escapes, then we can just return.
//
GuaranteeNullTermination();
pRead = (BYTE*)_pData;
while ( *pRead != '\0' )
{
if ( ( fAllowDoubleEscaping ||
!IsEscapeSequence( (CHAR*)pRead ) ) &&
ShouldEscape( *pRead ) )
{
dwNumEscapes++;
}
pRead++;
}
if ( dwNumEscapes == 0 )
{
goto Finished;
}
//
// Make sure that our cooked string buffer is big enough, so
// we can manipulate its pointer directly.
//
hr = Temp.Resize( _cbData + dwNumEscapes * 2 );
if ( FAILED (hr) )
{
goto Finished;
}
pRead = (BYTE*)_pData;
pWrite = (BYTE*)Temp.QueryStr();
while ( *pRead != '\0' )
{
if ( ( fAllowDoubleEscaping ||
!IsEscapeSequence( (CHAR*)pRead ) ) &&
ShouldEscape( *pRead ) )
{
_snprintf_s( szHex, 3, 2, "%02x", *pRead );
*pWrite = '%';
*(pWrite+1) = szHex[0];
*(pWrite+2) = szHex[1];
pRead++;
pWrite += 3;
continue;
}
*pWrite = *pRead;
pRead++;
pWrite++;
}
*pWrite = '\0';
Temp.CalcDataSize();
hr = SetData( Temp.QueryStr() );
if ( FAILED (hr) )
{
goto Finished;
}
Finished:
return hr;
}
VOID
Unescape(
VOID
)
{
CHAR * pRead;
CHAR * pWrite;
CHAR szHex[3] = {0};
BYTE c;
pRead = (CHAR*)_pData;
pWrite = pRead;
while ( *pRead )
{
if ( IsEscapeSequence( pRead ) )
{
szHex[0] = *(pRead+1);
szHex[1] = *(pRead+2);
c = (BYTE)strtoul( szHex, NULL, 16 );
*pWrite = c;
pRead += 3;
pWrite++;
continue;
}
*pWrite = *pRead;
pRead++;
pWrite++;
}
*pWrite = '\0';
CalcDataSize();
return;
}
VOID
MoveToFront(
DWORD cbOffset
)
{
if ( cbOffset >= _cbData )
{
Reset();
return;
}
MoveMemory( _pData, _pData + cbOffset, _cbData - cbOffset );
_cbData -= cbOffset;
}
BOOL
IsWildcardMatch(
LPCSTR szExpr
)
{
LPCSTR pExpr = szExpr;
LPCSTR pString = QueryStr();
LPCSTR pSubMatch;
DWORD cchSubMatch;
if ( !pExpr )
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
while ( *pExpr )
{
switch ( *pExpr )
{
case '*':
//
// Eat '*' characters
//
while ( *pExpr == '*' )
{
pExpr++;
}
//
// Find the next wildcard
//
pSubMatch = strchr( pExpr, '*' );
cchSubMatch = (DWORD)(pSubMatch ?
pSubMatch - pExpr :
strlen( pExpr ));
if ( cchSubMatch == 0 )
{
//
// No submatch. The rest of
// pString automatically matches
//
return TRUE;
}
//
// Ensure that the current submatch exists
//
while ( _strnicmp( pString, pExpr, cchSubMatch ) )
{
pString++;
if ( *pString == '\0' )
{
//
// Not found
//
return FALSE;
}
}
pExpr += cchSubMatch;
pString += cchSubMatch;
break;
default:
if ( TO_UPPER( *pExpr ) != TO_UPPER( *pString ) )
{
return FALSE;
}
pExpr++;
pString++;
}
}
if ( *pString != '\0' )
{
return FALSE;
}
return TRUE;
}
private:
LPBYTE _pData;
DWORD _cbData;
DWORD _cbBuffer;
DWORD _cbMaxAlloc;
BYTE _Inline[STB_INLINE_SIZE+2];
VOID
GuaranteeNullTermination()
{
_pData[_cbData] = 0;
_pData[_cbData+1] = 0;
}
BOOL
IsEscapeSequence(
CHAR * str
)
{
if ( *str == '%' &&
isxdigit( *(str+1) ) &&
isxdigit( *(str+2) ) )
{
return TRUE;
}
return FALSE;
}
BOOL
ShouldEscape(
BYTE c
)
{
//
// If the character is listed in RFC2396, section
// 2.4.3 as control, space, delims or unwise, we
// should escape it. Also, we should escape characters
// with the high bit set.
//
if ( c <= 0x1f ||
c == 0x7f )
{
//
// Control character
//
goto ReturnTrue;
}
if ( c >= 0x80 )
{
//
// High bit set
//
goto ReturnTrue;
}
switch ( c )
{
//
// space
//
case ' ':
//
// delims
//
case '<':
case '>':
case '#':
case '%':
case '\"':
//
// unwise
//
case '{':
case '}':
case '|':
case '\\':
case '^':
case '[':
case ']':
case '`':
goto ReturnTrue;
}
//
// If we get here, then the character should not be
// escaped
//
return FALSE;
ReturnTrue:
return TRUE;
}
};
#endif // _STBUFF_H