aspnetcore/src/IISLib/multisza.cpp

407 lines
8.5 KiB
C++

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
#include "precomp.h"
#include "multisza.h"
#include <tchar.h>
//
// Private Definitions
//
#define MAXULONG 4294967295
#define ISWHITE( ch ) ((ch) == L' ' || (ch) == L'\t' || (ch) == L'\r')
//
// When appending data, this is the extra amount we request to avoid
// reallocations
//
#define STR_SLOP 128
DWORD
MULTISZA::CalcLength( const CHAR * str,
LPDWORD pcStrings )
{
DWORD count = 0;
DWORD total = 1;
DWORD len;
while( *str ) {
len = ::strlen( str ) + 1;
total += len;
str += len;
count++;
}
if( pcStrings != NULL ) {
*pcStrings = count;
}
return total;
} // MULTISZA::CalcLength
BOOL
MULTISZA::FindString( const CHAR * str )
{
CHAR * multisz;
//
// Sanity check.
//
DBG_ASSERT( QueryStr() != NULL );
DBG_ASSERT( str != NULL );
DBG_ASSERT( *str != '\0' );
//
// Scan it.
//
multisz = QueryStr();
while( *multisz != '\0' ) {
if( !::strcmp( multisz, str ) ) {
return TRUE;
}
multisz += ::strlen( multisz ) + 1;
}
return FALSE;
} // MULTISZA::FindString
BOOL
MULTISZA::FindStringNoCase( const CHAR * str )
{
CHAR * multisz;
//
// Sanity check.
//
DBG_ASSERT( QueryStr() != NULL );
DBG_ASSERT( str != NULL );
DBG_ASSERT( *str != '\0' );
//
// Scan it.
//
multisz = QueryStr();
while( *multisz != '\0' ) {
if( !_stricmp( multisz, str ) ) {
return TRUE;
}
multisz += strlen( multisz ) + 1;
}
return FALSE;
} // MULTISZA::FindStringNoCase
VOID
MULTISZA::AuxInit( const CHAR * pInit )
{
BOOL fRet;
if ( pInit )
{
DWORD cStrings;
int cbCopy = CalcLength( pInit, &cStrings ) * sizeof(CHAR);
fRet = Resize( cbCopy );
if ( fRet ) {
CopyMemory( QueryPtr(), pInit, cbCopy );
m_cchLen = (cbCopy)/sizeof(CHAR);
m_cStrings = cStrings;
} else {
// BUFFER::SetValid( FALSE);
}
} else {
Reset();
}
} // MULTISZA::AuxInit()
/*******************************************************************
NAME: MULTISZA::AuxAppend
SYNOPSIS: Appends the string onto the MULTISZA.
ENTRY: Object to append
********************************************************************/
BOOL MULTISZA::AuxAppend( const CHAR * pStr, UINT cbStr, BOOL fAddSlop )
{
DBG_ASSERT( pStr != NULL );
UINT cbThis = QueryCB();
if( cbThis == 2 ) {
//
// It's empty, so start at the beginning.
//
cbThis = 0;
} else {
//
// It's not empty, so back up over the final terminating NULL.
//
cbThis -= sizeof(CHAR);
}
//
// Only resize when we have to. When we do resize, we tack on
// some extra space to avoid extra reallocations.
//
// Note: QuerySize returns the requested size of the string buffer,
// *not* the strlen of the buffer
//
//AcIncrement( CacMultiszAppend);
//
// Check for the arithmetic overflow
//
// ( 2 * sizeof( CHAR ) ) is for the double terminator
//
ULONGLONG cb64Required = (ULONGLONG)cbThis + cbStr + 2 * sizeof(CHAR);
if ( cb64Required > MAXULONG )
{
SetLastError( ERROR_ARITHMETIC_OVERFLOW );
return FALSE;
}
if ( QuerySize() < (DWORD) cb64Required )
{
ULONGLONG cb64AllocSize = cb64Required + (fAddSlop ? STR_SLOP : 0 );
//
// Check for the arithmetic overflow
//
if ( cb64AllocSize > MAXULONG )
{
SetLastError( ERROR_ARITHMETIC_OVERFLOW );
return FALSE;
}
if ( !Resize( (DWORD) cb64AllocSize ) )
return FALSE;
}
// copy the exact string and tack on the double terminator
memcpy( (BYTE *) QueryPtr() + cbThis,
pStr,
cbStr);
*(CHAR *)((BYTE *)QueryPtr() + cbThis + cbStr) = L'\0';
*(CHAR *)((BYTE *)QueryPtr() + cbThis + cbStr + sizeof(CHAR) ) = L'\0';
m_cchLen = CalcLength( (const CHAR *)QueryPtr(), &m_cStrings );
return TRUE;
} // MULTISZA::AuxAppend()
BOOL
MULTISZA::CopyToBuffer( __out_ecount_opt(*lpcch) CHAR * lpszBuffer, LPDWORD lpcch) const
/*++
Description:
Copies the string into the CHAR buffer passed in if the buffer
is sufficient to hold the translated string.
If the buffer is small, the function returns small and sets *lpcch
to contain the required number of characters.
Arguments:
lpszBuffer pointer to CHAR buffer which on return contains
the string on success.
lpcch pointer to DWORD containing the length of the buffer.
If *lpcch == 0 then the function returns TRUE with
the count of characters required stored in lpcch.
Also in this case lpszBuffer is not affected.
Returns:
TRUE on success.
FALSE on failure. Use GetLastError() for further details.
--*/
{
BOOL fReturn = TRUE;
if ( lpcch == NULL) {
SetLastError( ERROR_INVALID_PARAMETER);
return ( FALSE);
}
register DWORD cch = QueryCCH();
if ( *lpcch >= cch) {
DBG_ASSERT( lpszBuffer);
memcpy( lpszBuffer, QueryStr(), cch * sizeof(CHAR));
} else {
DBG_ASSERT( *lpcch < cch);
SetLastError( ERROR_INSUFFICIENT_BUFFER);
fReturn = FALSE;
}
*lpcch = cch;
return ( fReturn);
} // MULTISZA::CopyToBuffer()
BOOL
MULTISZA::Equals(
MULTISZA* pmszRhs
)
//
// Compares this to pmszRhs, returns TRUE if equal
//
{
DBG_ASSERT( NULL != pmszRhs );
PCSTR pszLhs = First( );
PCSTR pszRhs = pmszRhs->First( );
if( m_cStrings != pmszRhs->m_cStrings )
{
return FALSE;
}
while( NULL != pszLhs )
{
DBG_ASSERT( NULL != pszRhs );
if( 0 != strcmp( pszLhs, pszRhs ) )
{
return FALSE;
}
pszLhs = Next( pszLhs );
pszRhs = pmszRhs->Next( pszRhs );
}
return TRUE;
}
HRESULT
SplitCommaDelimitedString(
PCSTR pszList,
BOOL fTrimEntries,
BOOL fRemoveEmptyEntries,
MULTISZA * pmszList
)
/*++
Routine Description:
Split comma delimited string into a MULTISZA. Additional leading empty
entries after the first are discarded.
Arguments:
pszList - List to split up
fTrimEntries - Whether each entry should be trimmed before added to MULTISZA
fRemoveEmptyEntries - Whether empty entires should be discarded
pmszList - Filled with MULTISZA list
Return Value:
HRESULT
--*/
{
HRESULT hr = S_OK;
if ( pszList == NULL ||
pmszList == NULL )
{
DBG_ASSERT( FALSE );
hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
goto Finished;
}
pmszList->Reset();
/*
pszCurrent: start of the current entry which may be the comma that
precedes the next entry if the entry is empty
pszNext: the comma that precedes the next entry. If
pszCurrent == pszNext, then the entry is empty
pszEnd: just past the end of the current entry
*/
for ( PCSTR pszCurrent = pszList,
pszNext = strchr( pszCurrent, L',' )
;
;
pszCurrent = pszNext + 1,
pszNext = strchr( pszCurrent, L',' ) )
{
PCSTR pszEnd = NULL;
if ( pszNext != NULL )
{
pszEnd = pszNext;
}
else
{
pszEnd = pszCurrent + strlen( pszCurrent );
}
if ( fTrimEntries )
{
while ( pszCurrent < pszEnd && ISWHITE( pszCurrent[ 0 ] ) )
{
pszCurrent++;
}
while ( pszEnd > pszCurrent && ISWHITE( pszEnd[ -1 ] ) )
{
pszEnd--;
}
}
if ( pszCurrent != pszEnd || !fRemoveEmptyEntries )
{
if ( !pmszList->Append( pszCurrent, (DWORD) ( pszEnd - pszCurrent ) ) )
{
hr = HRESULT_FROM_WIN32( GetLastError() );
goto Finished;
}
}
if ( pszNext == NULL )
{
break;
}
}
Finished:
return hr;
}