windows-nt/Source/XPSP1/NT/inetsrv/query/web/dll/tokstr.cxx
2020-09-26 16:20:57 +08:00

563 lines
14 KiB
C++

//+---------------------------------------------------------------------------
//
// Copyright (C) 1996, Microsoft Corporation.
//
// File: tokstr.cxx
//
// Contents: Used to break down a string into its tokens
//
// History: 96/Feb/13 DwightKr Created
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
//+---------------------------------------------------------------------------
//
// Method: CTokenizeString::CTokenizeString - public constructor
//
// History: 96/Jan/23 DwightKr Created
//
//----------------------------------------------------------------------------
CTokenizeString::CTokenizeString( WCHAR const * wcsString ) :
_wcsString(wcsString),
_wcsCurrentToken(wcsString),
_wcsNextToken(wcsString)
{
Accept();
}
//+---------------------------------------------------------------------------
//
// Method: CTokenizeString::Accept - public
//
// History: 96/Jan/23 DwightKr Created
//
//----------------------------------------------------------------------------
void CTokenizeString::Accept()
{
EatWhiteSpace();
_wcsCurrentToken = _wcsNextToken;
switch ( *_wcsCurrentToken )
{
case L'"':
_wcsNextToken++;
_token = QUOTES_TOKEN;
break;
case L'{':
_wcsNextToken++;
_token = C_OPEN_TOKEN;
break;
case L'}':
_wcsNextToken++;
_token = C_CLOSE_TOKEN;
break;
case L',':
_wcsNextToken++;
_token = COMMA_TOKEN;
break;
case 0:
_token = EOS_TOKEN;
break;
default:
_wcsNextToken = _wcsCurrentToken + wcscspn( _wcsCurrentToken, WORD_STR );
_token = TEXT_TOKEN;
break;
}
}
//+---------------------------------------------------------------------------
//
// Member: CTokenizeString:AcqWord, public
//
// Synopsis: Copies the word that _wcsCurrentToken is pointing to and
// returns the new string. Positions _wcsCurrentToken after
// the word and whitespace. Returns 0 if at the end of a
// TEXT_TOKEN.
//
// History: 96-Feb-13 DwightKr Created.
//
//----------------------------------------------------------------------------
WCHAR * CTokenizeString::AcqWord()
{
if ( IsEndOfTextToken() )
return 0;
WCHAR const * pEnd = _wcsNextToken;
int cwcToken = (int)(pEnd - _wcsCurrentToken + 1);
WCHAR * newBuf = new WCHAR [ cwcToken ];
RtlCopyMemory( newBuf, _wcsCurrentToken, cwcToken * sizeof(WCHAR));
newBuf[cwcToken-1] = 0;
_wcsCurrentToken = pEnd;
while ( iswspace(*_wcsCurrentToken) )
_wcsCurrentToken++;
return newBuf;
}
//+---------------------------------------------------------------------------
//
// Member: CTokenizeString::GetNumber, public
//
// Synopsis: If _text is at the end of the TEXT_TOKEN, returns FALSE.
// If not, puts the unsigned _int64 from the scanner into number
// and returns TRUE.
//
// Arguments: [number] -- the unsigned _int64 which will be changed and
// passed back out as the ULONG from the scanner.
//
// Notes: May be called several times in a loop before Accept() is
// called.
//
// History: 96-Feb-13 AmyA Created
//
//----------------------------------------------------------------------------
BOOL CTokenizeString::GetNumber( unsigned _int64 & number )
{
ULONG base = 10;
WCHAR const * wcsCurrentToken = _wcsCurrentToken;
if ( IsEndOfTextToken() ||
!iswdigit(*_wcsCurrentToken) ||
(*_wcsCurrentToken == L'-') )
{
return FALSE;
}
if ( _wcsCurrentToken[0] == L'0' &&
(_wcsCurrentToken[1] == L'x' || _wcsCurrentToken[1] == L'X'))
{
_wcsCurrentToken += 2;
base = 16;
}
number = _wcstoui64( _wcsCurrentToken, (WCHAR **)(&_wcsCurrentToken), base );
//
// looks like a real number?
//
if ( ( wcsCurrentToken == _wcsCurrentToken ) ||
( L'.' == *_wcsCurrentToken ) )
{
_wcsCurrentToken = wcsCurrentToken;
return FALSE;
}
while ( iswspace(*_wcsCurrentToken) )
_wcsCurrentToken++;
return TRUE;
}
//+---------------------------------------------------------------------------
//
// Member: CTokenizeString::GetNumber, public
//
// Synopsis: If _wcsCurrentToken is at the end of the TEXT_TOKEN, returns FALSE.
// If not, puts the _int64 from the scanner into number and
// returns TRUE.
//
// Arguments: [number] -- the _int64 which will be changed and passed back
// out as the _int64 from the scanner.
//
// Notes: May be called several times in a loop before Accept() is
// called.
//
// History: 96-Feb-13 DwightKr Created
//
//----------------------------------------------------------------------------
BOOL CTokenizeString::GetNumber( _int64 & number )
{
WCHAR *text = (WCHAR *) _wcsCurrentToken;
BOOL IsNegative = FALSE;
if ( L'-' == _wcsCurrentToken[0] )
{
IsNegative = TRUE;
_wcsCurrentToken++;
}
unsigned _int64 ui64Number;
if ( !GetNumber( ui64Number ) )
{
_wcsCurrentToken = text;
return FALSE;
}
if ( IsNegative )
{
if ( ui64Number > 0x8000000000000000L )
{
_wcsCurrentToken = text;
return FALSE;
}
number = -((_int64) ui64Number);
}
else
{
number = (_int64) ui64Number;
}
return TRUE;
}
//+---------------------------------------------------------------------------
//
// Member: CTokenizeString::GetNumber, public
//
// Synopsis: If _wcsCurrentToken is at the end of the TEXT_TOKEN, returns FALSE.
// If not, puts the LONG from the scanner into number and
// returns TRUE.
//
// Arguments: [number] -- the double which will be changed and passed back
// out as the double from the scanner.
//
// Notes: May be called several times in a loop before Accept() is
// called.
//
// History: 96-Feb-13 DwightKr Created
//
//----------------------------------------------------------------------------
BOOL CTokenizeString::GetNumber( double & number )
{
if ( IsEndOfTextToken() ||
((L'-' != *_wcsCurrentToken) &&
(iswdigit(*_wcsCurrentToken) == 0) )
)
{
return FALSE;
}
if ( swscanf( _wcsCurrentToken, L"%lf", &number ) != 1 )
{
return FALSE;
}
while ( iswspace(*_wcsCurrentToken) != 0 )
_wcsCurrentToken++;
return TRUE;
}
//+---------------------------------------------------------------------------
//
// Member: CTokenizeString::GetGUID, public
//
// Synopsis: If _wcsCurrentToken is at the end of the TEXT_TOKEN, returns FALSE.
// If not, puts the guid into guid & returns TRUE;
//
// Arguments: [guid] -- the guid which will be changed and passed back
// out as the output from the scanner.
//
// Notes: May be called several times in a loop before Accept() is
// called.
//
// History: 96-Feb-13 DwightKr Created
//
//----------------------------------------------------------------------------
BOOL CTokenizeString::GetGUID( GUID & guid )
{
if ( IsEndOfTextToken() || !iswdigit(*_wcsCurrentToken) )
return FALSE;
// 0123456789 123456789 123456789 123456
// A guid MUST have the syntax XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
//
//
// Don't use wsscanf. We're scanning into *bytes*, but wsscanf assumes
// result locations are *dwords*. Thus a write to the last few bytes of
// the guid writes over other memory!
//
WCHAR wcsGuid[37];
RtlZeroMemory( wcsGuid, sizeof(wcsGuid) );
wcsncpy( wcsGuid, _wcsCurrentToken, 36 );
if ( wcsGuid[8] != L'-' )
return FALSE;
wcsGuid[8] = 0;
WCHAR * pwcStart = &wcsGuid[0];
WCHAR * pwcEnd;
guid.Data1 = wcstoul( pwcStart, &pwcEnd, 16 );
if ( pwcEnd < &wcsGuid[8] ) // Non-digit found before wcsGuid[8]
return FALSE;
if ( wcsGuid[13] != L'-' )
return FALSE;
wcsGuid[13] = 0;
pwcStart = &wcsGuid[9];
guid.Data2 = (USHORT)wcstoul( pwcStart, &pwcEnd, 16 );
if ( pwcEnd < &wcsGuid[13] )
return FALSE;
if ( wcsGuid[18] != L'-' )
return FALSE;
wcsGuid[18] = 0;
pwcStart = &wcsGuid[14];
guid.Data3 = (USHORT)wcstoul( pwcStart, &pwcEnd, 16 );
if ( pwcEnd < &wcsGuid[18] )
return FALSE;
WCHAR wc = wcsGuid[21];
wcsGuid[21] = 0;
pwcStart = &wcsGuid[19];
guid.Data4[0] = (unsigned char)wcstoul( pwcStart, &pwcEnd, 16 );
if ( pwcEnd < &wcsGuid[21] )
return FALSE;
wcsGuid[21] = wc;
if ( wcsGuid[23] != L'-' )
return FALSE;
wcsGuid[23] = 0;
pwcStart = &wcsGuid[21];
guid.Data4[1] = (unsigned char)wcstoul( pwcStart, &pwcEnd, 16 );
if ( pwcEnd < &wcsGuid[23] )
return FALSE;
for ( unsigned i = 0; i < 6; i++ )
{
wc = wcsGuid[26+i*2];
wcsGuid[26+i*2] = 0;
pwcStart = &wcsGuid[24+i*2];
guid.Data4[2+i] = (unsigned char)wcstoul( pwcStart, &pwcEnd, 16 );
if ( pwcEnd < &wcsGuid[26+i*2] )
return FALSE;
wcsGuid[26+i*2] = wc;
}
_wcsCurrentToken += 36;
_wcsNextToken = _wcsCurrentToken;
EatWhiteSpace();
return TRUE;
}
//+---------------------------------------------------------------------------
//
// Member: CTokenizeString::AcqPhrase, public
//
// Synopsis: gets all characters up to end-of-line or next quote
//
// History: 96-Feb-13 DwightKr Created
//
//----------------------------------------------------------------------------
WCHAR * CTokenizeString::AcqPhrase()
{
//
// Find the closing "
//
WCHAR const * wcsClosingQuote = _wcsCurrentToken;
do
{
if ( 0 == *wcsClosingQuote )
break;
if ( L'"' == *wcsClosingQuote )
{
if ( L'"' == *(wcsClosingQuote+1) )
wcsClosingQuote++;
else
break;
}
wcsClosingQuote++;
} while ( TRUE );
//
// We've found the closing quote. Build a buffer big enough to
// contain the string.
//
ULONG cwcToken = (ULONG)(wcsClosingQuote - _wcsCurrentToken + 1);
XArray<WCHAR> wcsToken( cwcToken );
//
// copy the string, but remove the extra quote characters
//
WCHAR * pwcNewBuf = wcsToken.GetPointer();
WCHAR const * pStart = _wcsCurrentToken;
while ( pStart < wcsClosingQuote )
{
*pwcNewBuf++ = *pStart++;
if ( L'"' == *pStart )
pStart++;
}
*pwcNewBuf = 0;
_wcsCurrentToken += cwcToken - 1;
_wcsNextToken = _wcsCurrentToken;
EatWhiteSpace();
return wcsToken.Acquire();
}
//+---------------------------------------------------------------------------
//
// Member: CTokenizeString::AcqVector, public
//
// Synopsis: Gets each of the vector elements upto the next }
//
// History: 96-Feb-13 DwightKr Created
//
//----------------------------------------------------------------------------
void CTokenizeString::AcqVector( PROPVARIANT & propVariant )
{
//
// Determine the VT type of this vector.
//
GUID guid;
_int64 i64Value;
double dblValue;
if ( GetGUID( guid ) )
{
propVariant.vt = VT_CLSID | VT_VECTOR;
propVariant.cauuid.cElems = 0;
CDynArrayInPlace<GUID> pElems;
do
{
Accept();
pElems.Add( guid, propVariant.cauuid.cElems );
propVariant.cauuid.cElems++;
if ( LookAhead() == COMMA_TOKEN )
{
Accept();
}
} while ( GetGUID( guid ) );
propVariant.cauuid.pElems = pElems.Acquire();
}
else if ( GetNumber( i64Value ) )
{
propVariant.vt = VT_I8 | VT_VECTOR;
propVariant.cah.cElems = 0;
CDynArrayInPlace<_int64> pElems;
do
{
Accept();
pElems.Add( i64Value, propVariant.cah.cElems );
propVariant.cah.cElems++;
if ( LookAhead() == COMMA_TOKEN )
{
Accept();
}
} while ( GetNumber( i64Value ) );
propVariant.cah.pElems = (LARGE_INTEGER *) pElems.Acquire();
}
else if ( GetNumber( dblValue ) )
{
propVariant.vt = VT_R8 | VT_VECTOR;
propVariant.cadbl.cElems = 0;
CDynArrayInPlace<double> pElems;
do
{ Accept();
pElems.Add( dblValue, propVariant.cadbl.cElems );
propVariant.cadbl.cElems++;
if ( LookAhead() == COMMA_TOKEN )
{
Accept();
}
} while ( GetNumber( dblValue ) );
propVariant.cadbl.pElems = pElems.Acquire();
}
else
{
propVariant.vt = VT_LPWSTR | VT_VECTOR;
CDynArrayInPlace<WCHAR *> pElems;
propVariant.calpwstr.cElems = 0;
while ( (LookAhead() != C_CLOSE_TOKEN) &&
(LookAhead() != EOS_TOKEN)
)
{
//
// If its a quoted string, get everything between the quotes.
//
if ( LookAhead() == QUOTES_TOKEN )
{
Accept(); // Skip over the quote
pElems.Add(AcqPhrase(), propVariant.calpwstr.cElems );
Accept(); // Skip over the string
if ( LookAhead() != QUOTES_TOKEN )
{
THROW( CHTXException(MSG_CI_HTX_MISSING_QUOTE, 0, 0) );
}
Accept(); // Skip over the quote
}
else
{
//
// Get the next word
//
pElems.Add( AcqWord(), propVariant.calpwstr.cElems );
Accept(); // Skip over the string
}
propVariant.calpwstr.cElems++;
if ( LookAhead() == COMMA_TOKEN )
{
Accept();
}
}
propVariant.calpwstr.pElems = pElems.Acquire();
}
}