Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

813 lines
18 KiB

/*==========================================================================
*
* Copyright (C) 2000-2002 Microsoft Corporation. All Rights Reserved.
*
* File: ClassFac.cpp
* Content: Parsing engine
*@@BEGIN_MSINTERNAL
* History:
* Date By Reason
* ==== == ======
* 02/04/2000 rmt Created
* 02/17/2000 rmt Parameter validation work
* 02/21/2000 rmt Updated to make core Unicode and remove ANSI calls
* 03/21/2000 rmt Renamed all DirectPlayAddress8's to DirectPlay8Addresses
* 07/21/2000 rmt Bug #39940 - Addressing library doesn't properly parse stopbits in URLs
*@@END_MSINTERNAL
*
***************************************************************************/
#include "dnaddri.h"
#undef DPF_MODNAME
#define DPF_MODNAME "DP8ADDRESSPARSE::DP8ADDRESSPARSE"
DP8ADDRESSPARSE::DP8ADDRESSPARSE(
): m_pwszCurrentLocation(NULL),
m_pwszCurrentKey(NULL),
m_pwszCurrentValue(NULL),
m_pbUserData(NULL),
m_dwUserDataSize(0),
m_dp8State(DP8AP_IDLE),
m_dwLenURL(0)
{
}
#undef DPF_MODNAME
#define DPF_MODNAME "DP8ADDRESSPARSE::~DP8ADDRESSPARSE"
DP8ADDRESSPARSE::~DP8ADDRESSPARSE()
{
if( m_pwszCurrentKey != NULL )
{
DNFree(m_pwszCurrentKey);
}
if( m_pwszCurrentValue != NULL )
{
DNFree(m_pwszCurrentValue);
}
if ( m_pbUserData != NULL )
{
DNFree(m_pbUserData);
}
}
#undef DPF_MODNAME
#define DPF_MODNAME "DP8ADDRESSPARSE::ParseURL"
HRESULT DP8ADDRESSPARSE::ParseURL( DP8ADDRESSOBJECT *dp8aObject, WCHAR *pstrURL )
{
HRESULT hr;
if( m_pwszCurrentKey != NULL )
{
DNFree(m_pwszCurrentKey);
m_pwszCurrentKey = NULL;
}
if( m_pwszCurrentValue != NULL )
{
DNFree(m_pwszCurrentValue);
m_pwszCurrentValue = NULL;
}
if( m_pbUserData != NULL )
{
DNFree(m_pbUserData);
m_pbUserData = NULL;
}
m_dwUserDataSize = 0;
m_pwszCurrentLocation = pstrURL;
m_dwLenURL = wcslen(pstrURL);
if( m_dwLenURL < wcslen( DPNA_HEADER ) )
{
DPFX(DPFPREP, 0, "Invalid URL" );
return DPNERR_INVALIDURL;
}
if( wcsncmp( pstrURL, DPNA_HEADER, wcslen(DPNA_HEADER) ) != 0 )
{
DPFX(DPFPREP, 0, "No header, invalid URL" );
return DPNERR_INVALIDURL;
}
m_pwszCurrentLocation += wcslen( DPNA_HEADER );
m_pwszCurrentKey = (WCHAR*) DNMalloc((m_dwLenURL+1)*sizeof(WCHAR));
if( !m_pwszCurrentKey )
{
DPFX(DPFPREP, 0, "Error allocating memory" );
return DPNERR_OUTOFMEMORY;
}
m_pwszCurrentValue = (WCHAR*) DNMalloc((m_dwLenURL+1)*sizeof(WCHAR));
if( !m_pwszCurrentValue )
{
DNFree(m_pwszCurrentKey);
m_pwszCurrentKey = NULL;
DPFX(DPFPREP, 0, "Error allocating memory" );
return DPNERR_OUTOFMEMORY;
}
m_pbUserData = (BYTE*) DNMalloc(m_dwLenURL+1);
if( !m_pbUserData )
{
DNFree(m_pwszCurrentKey);
DNFree(m_pwszCurrentValue);
m_pwszCurrentKey = NULL;
m_pwszCurrentValue = NULL;
DPFX(DPFPREP, 0, "Error allocating memory" );
return DPNERR_OUTOFMEMORY;
}
m_dp8State = DP8AP_IDLE;
// Loop until the string is done
while( *m_pwszCurrentLocation != L'\0' )
{
switch( m_dp8State )
{
case DP8AP_IDLE:
if( *m_pwszCurrentLocation == DPNA_SEPARATOR_USERDATA )
{
m_dp8State = DP8AP_USERDATA;
m_pwszCurrentLocation++;
}
else
{
m_dp8State = DP8AP_KEY;
}
break;
case DP8AP_KEY:
if( *m_pwszCurrentLocation == DPNA_SEPARATOR_USERDATA )
{
m_dp8State = DP8AP_USERDATA;
m_pwszCurrentLocation++;
break;
}
hr = FSM_Key();
if( FAILED( hr ) )
{
DPFX(DPFPREP, 0, "Error parsing key hr = 0x%x", hr );
return hr;
}
// Parse ended with an equals
if( *m_pwszCurrentLocation == DPNA_SEPARATOR_KEYVALUE )
{
m_dp8State = DP8AP_VALUE;
m_pwszCurrentLocation++;
}
else
{
DPFX(DPFPREP, 0, "keyname without associated value hr=0x%x", hr );
return DPNERR_INVALIDURL;
}
break;
case DP8AP_VALUE:
hr = FSM_Value();
if( FAILED( hr ) )
{
DPFX(DPFPREP, 0, "Error parsing value hr=0x%x", hr );
return hr;
}
// Parse ended with an equals
if( *m_pwszCurrentLocation == DPNA_SEPARATOR_COMPONENT )
{
m_dp8State = DP8AP_KEY;
m_pwszCurrentLocation++;
}
else if( *m_pwszCurrentLocation == DPNA_SEPARATOR_USERDATA )
{
m_dp8State = DP8AP_USERDATA;
m_pwszCurrentLocation++;
}
else if( *m_pwszCurrentLocation == L'\0' )
{
m_dp8State = DP8AP_IDLE;
}
else
{
DPFX(DPFPREP, 0, "Error parsing next key" );
hr = DPNERR_INVALIDURL;
return hr;
}
hr = FSM_CommitEntry(dp8aObject);
if( hr == DPNERR_INVALIDPARAM )
{
DPFX(DPFPREP, 0, "Invalid value specified in URL hr=0x%x", hr );
hr = DPNERR_INVALIDURL;
return hr;
}
else if( FAILED( hr ) )
{
DPFX(DPFPREP, 0, "Error commiting entry hr=0x%x", hr );
return hr;
}
break;
case DP8AP_USERDATA:
hr = FSM_UserData();
if( FAILED( hr ) )
{
DPFX(DPFPREP, 0, "Error parsing user data hr=0x%x", hr );
return hr;
}
hr = dp8aObject->SetUserData( m_pbUserData, m_dwUserDataSize );
if( FAILED( hr ) )
{
DPFX(DPFPREP, 0, "Error setting user data hr=0x%x", hr );
return hr;
}
break;
}
}
if( m_dp8State != DP8AP_IDLE &&
m_dp8State != DP8AP_USERDATA )
{
DPFX(DPFPREP, 0, "Parsing error hr=0x%x", hr );
hr = DPNERR_INVALIDURL;
return hr;
}
return DPN_OK;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DP8ADDRESSPARSE::IsValidKeyChar"
BOOL DP8ADDRESSPARSE::IsValidKeyChar( WCHAR ch )
{
if( ch >= L'A' && ch <= L'Z' )
return TRUE;
if( ch >= L'a' && ch <= L'z' )
return TRUE;
if( ch >= L'0' && ch <= L'9' )
return TRUE;
if( ch == L'-' || ch == L'?' || ch == L'.' ||
ch == L',' || ch == L'+' || ch == L'_' )
return TRUE;
return FALSE;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DP8ADDRESSPARSE::IsValidKeyTerminator"
BOOL DP8ADDRESSPARSE::IsValidKeyTerminator( WCHAR ch )
{
if( ch == 0 )
return TRUE;
if( ch == DPNA_SEPARATOR_USERDATA )
return TRUE;
if( ch == DPNA_SEPARATOR_COMPONENT )
return TRUE;
if( ch == DPNA_SEPARATOR_KEYVALUE )
return TRUE;
return FALSE;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DP8ADDRESSPARSE::FSM_Key"
// FSM_Key
//
// Parse a keyname, or return an error on error
//
HRESULT DP8ADDRESSPARSE::FSM_Key()
{
DWORD dwKeyLoc = 0;
m_pwszCurrentKey[0] = 0;
HRESULT hr = DPN_OK;
while( 1 )
{
if( IsValidKeyChar(*m_pwszCurrentLocation) )
{
m_pwszCurrentKey[dwKeyLoc] = *m_pwszCurrentLocation;
}
else if( IsValidKeyTerminator(*m_pwszCurrentLocation) )
{
m_pwszCurrentKey[dwKeyLoc] = 0;
break;
}
else
{
m_pwszCurrentKey[dwKeyLoc] = 0;
hr = DPNERR_INVALIDURL;
break;
}
dwKeyLoc++;
m_pwszCurrentLocation++;
}
return hr;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DP8ADDRESSPARSE::IsValidNumber"
BOOL DP8ADDRESSPARSE::IsValidNumber( WCHAR ch )
{
if( ch < L'0' ||
ch > L'9' )
{
return FALSE;
}
else
{
return TRUE;
}
}
#undef DPF_MODNAME
#define DPF_MODNAME "DP8ADDRESSPARSE::IsValidHex"
BOOL DP8ADDRESSPARSE::IsValidHex( WCHAR ch )
{
if( IsValidNumber( ch ) )
return TRUE;
if( ch >= L'A' || ch <= L'F' )
return TRUE;
if( ch >= L'a' || ch <= L'f' )
return TRUE;
return FALSE;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DP8ADDRESSPARSE::HexToChar"
WCHAR DP8ADDRESSPARSE::HexToChar( const WCHAR *sz )
{
WCHAR chResult = sz[0];
// First digit
if( sz[0] >= L'0' && sz[0] <= L'9' )
chResult = sz[0]-L'0';
if( sz[0] >= L'A' && sz[0] <= L'F' )
chResult = sz[0]-L'A'+10;
if( sz[0] >= L'a' && sz[0] <= L'f' )
chResult = sz[0]-L'a'+10;
chResult <<= 4;
// Second digit
if( sz[1] >= L'0' && sz[1] <= L'9' )
chResult += sz[1]-'0';
if( sz[1] >= L'A' && sz[1] <= L'F' )
chResult += sz[1]-L'A'+10;
if( sz[1] >= L'a' && sz[1] <= L'f' )
chResult += sz[1]-L'a'+10;
return chResult;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DP8ADDRESSPARSE::FSM_Value"
HRESULT DP8ADDRESSPARSE::FSM_Value()
{
m_fNonNumeric = FALSE;
m_pwszCurrentValue[0] = 0;
HRESULT hr = DPN_OK;
m_dwValueLen = 0;
while( 1 )
{
// Just add it
if( IsValidKeyChar( *m_pwszCurrentLocation ) )
{
m_pwszCurrentValue[m_dwValueLen] = *m_pwszCurrentLocation;
if( !IsValidNumber( *m_pwszCurrentLocation ) )
{
m_fNonNumeric = TRUE;
}
}
// ESCAPE SEQUENCE
else if( *m_pwszCurrentLocation == DPNA_ESCAPECHAR )
{
m_fNonNumeric = TRUE;
if( *(m_pwszCurrentLocation+1) == DPNA_ESCAPECHAR )
{
m_pwszCurrentValue[m_dwValueLen] = DPNA_ESCAPECHAR;
m_pwszCurrentLocation += 2;
}
if( wcslen( m_pwszCurrentLocation ) < 3 )
{
DPFX(DPFPREP, 0, "Unexpected end in escape sequence" );
hr = DPNERR_INVALIDURL;
break;
}
if( !IsValidHex( *(m_pwszCurrentLocation+1) ) ||
!IsValidHex( *(m_pwszCurrentLocation+2) ) )
{
DPFX(DPFPREP, 0, "Invalid escape sequence" );
hr = DPNERR_INVALIDURL;
break;
}
m_pwszCurrentLocation ++;
m_pwszCurrentValue[m_dwValueLen] = HexToChar(m_pwszCurrentLocation);
m_pwszCurrentLocation ++;
}
else if( IsValidKeyTerminator(*m_pwszCurrentLocation) )
{
m_pwszCurrentValue[m_dwValueLen] = 0;
break;
}
else
{
m_pwszCurrentValue[m_dwValueLen] = 0;
DPFX(DPFPREP, 0, "Unexpected character in URL" );
hr = DPNERR_INVALIDURL;
break;
}
m_dwValueLen++;
m_pwszCurrentLocation++;
}
if( m_dwValueLen < 1 )
{
DPFX(DPFPREP, DP8A_ERRORLEVEL, "0 length value" );
return DPNERR_INVALIDURL;
}
return hr;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DP8ADDRESSPARSE::FSM_UserData"
HRESULT DP8ADDRESSPARSE::FSM_UserData()
{
m_pwszCurrentValue[0] = 0;
HRESULT hr = DPN_OK;
DWORD dwValueLoc = 0;
while( 1 )
{
// Just add it
if( IsValidKeyChar( *m_pwszCurrentLocation ) )
{
m_pbUserData[dwValueLoc] = (CHAR) *m_pwszCurrentLocation;
}
// ESCAPE SEQUENCE
else if( *m_pwszCurrentLocation == DPNA_ESCAPECHAR )
{
if( *(m_pwszCurrentLocation+1) == DPNA_ESCAPECHAR )
{
m_pbUserData[dwValueLoc] = DPNA_ESCAPECHAR;
m_pwszCurrentLocation += 2;
}
if( wcslen( m_pwszCurrentLocation ) < 3 )
{
DPFX(DPFPREP, 0, "Unexpected end in escape sequence" );
hr = DPNERR_INVALIDURL;
break;
}
if( !IsValidHex( *(m_pwszCurrentLocation+1) ) ||
!IsValidHex( *(m_pwszCurrentLocation+2) ) )
{
DPFX(DPFPREP, 0, "Invalid escape sequence" );
hr = DPNERR_INVALIDURL;
break;
}
m_pwszCurrentLocation ++;
m_pbUserData[dwValueLoc] = (CHAR) HexToChar(m_pwszCurrentLocation);
m_pwszCurrentLocation ++;
}
else if( IsValidKeyTerminator(*m_pwszCurrentLocation) )
{
m_pwszCurrentValue[dwValueLoc] = 0;
break;
}
else
{
m_pwszCurrentValue[dwValueLoc] = 0;
hr = DPNERR_INVALIDURL;
break;
}
dwValueLoc++;
m_pwszCurrentLocation++;
}
m_dwUserDataSize = dwValueLoc;
return hr;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DP8ADDRESSPARSE::FSM_CommitEntry"
HRESULT DP8ADDRESSPARSE::FSM_CommitEntry(DP8ADDRESSOBJECT *pdp8aObject)
{
DWORD dwDataType = 0xFFFFFFFF;
// Ensure that datatype is correct in case the key is a reserved key
for( DWORD dwIndex = 0; dwIndex < c_dwNumBaseStrings; dwIndex++ )
{
if( _wcsicmp( g_szBaseStrings[dwIndex], m_pwszCurrentKey ) == 0 )
{
dwDataType = g_dwBaseRequiredTypes[dwIndex] ;
break;
}
}
// If it's numeric
if( (dwDataType == DPNA_DATATYPE_DWORD || dwDataType == 0xFFFFFFFF) && !m_fNonNumeric && wcslen(m_pwszCurrentValue)<=10)
{
DWORD dwTmpValue;
dwTmpValue = wcstoul( m_pwszCurrentValue, NULL, 10 );
return pdp8aObject->SetElement( m_pwszCurrentKey, &dwTmpValue, sizeof(DWORD), DPNA_DATATYPE_DWORD );
}
// We've read a GUID
if (dwDataType == DPNA_DATATYPE_GUID || dwDataType == 0xFFFFFFFF)
{
// L"{%8X-%4X-%4X-%2X%2X-%2X%2X%2X%2X%2X%2X}"
typedef enum
{
OpenBrace,
HexDWord1,
HexWord1,
HexWord2,
DoubleHexBytes,
HexBytes,
CloseBrace,
Invalid,
} GUID_PARSE_STATE;
GUID guidValue;
GUID_PARSE_STATE GuidParseState;
BOOL fStateChange;
ULARGE_INTEGER uliValue;
WCHAR * pwcStateStart;
WCHAR * pwcCurrent;
DWORD_PTR dwLength;
GuidParseState = OpenBrace;
fStateChange = FALSE;
uliValue.QuadPart = 0;
pwcCurrent = m_pwszCurrentValue;
pwcStateStart = pwcCurrent;
//
// Loop until we run out of string.
//
while ((*pwcCurrent) != 0)
{
switch (*pwcCurrent)
{
case L'0':
case L'1':
case L'2':
case L'3':
case L'4':
case L'5':
case L'6':
case L'7':
case L'8':
case L'9':
{
uliValue.QuadPart = uliValue.QuadPart * 16 + ((*pwcCurrent) - L'0');
break;
}
case L'a':
case L'b':
case L'c':
case L'd':
case L'e':
case L'f':
{
uliValue.QuadPart = uliValue.QuadPart * 16 + ((*pwcCurrent) - L'a' + 10);
break;
}
case L'A':
case L'B':
case L'C':
case L'D':
case L'E':
case L'F':
{
uliValue.QuadPart = uliValue.QuadPart * 16 + ((*pwcCurrent) - L'A' + 10);
break;
}
case L'{':
case L'}':
case L'-':
{
dwLength = ((DWORD_PTR) pwcCurrent) - ((DWORD_PTR) pwcStateStart);
switch (GuidParseState)
{
case OpenBrace:
{
if (((*pwcCurrent) == L'{') &&
(dwLength == 0))
{
fStateChange = TRUE;
}
else
{
GuidParseState = Invalid;
}
break;
}
case HexDWord1:
{
if (((*pwcCurrent) == L'-') &&
(dwLength <= (sizeof(DWORD) * 2 * sizeof(WCHAR))))
{
guidValue.Data1 = uliValue.LowPart;
fStateChange = TRUE;
}
else
{
GuidParseState = Invalid;
}
break;
}
case HexWord1:
{
if (((*pwcCurrent) == L'-') &&
(dwLength <= (sizeof(WORD) * 2 * sizeof(WCHAR))))
{
guidValue.Data2 = (WORD) uliValue.LowPart;
fStateChange = TRUE;
}
else
{
GuidParseState = Invalid;
}
break;
}
case HexWord2:
{
if (((*pwcCurrent) == L'-') &&
(dwLength <= (sizeof(WORD) * 2 * sizeof(WCHAR))))
{
guidValue.Data3 = (WORD) uliValue.LowPart;
fStateChange = TRUE;
}
else
{
GuidParseState = Invalid;
}
break;
}
case DoubleHexBytes:
{
if (((*pwcCurrent) == L'-') &&
(dwLength == (2 * 2 * sizeof(WCHAR))))
{
guidValue.Data4[0] = (BYTE) ((uliValue.LowPart & 0x0000FF00) >> 8);
guidValue.Data4[1] = (BYTE) (uliValue.LowPart & 0x000000FF);
fStateChange = TRUE;
}
else
{
GuidParseState = Invalid;
}
break;
}
case HexBytes:
{
if (((*pwcCurrent) == L'}') &&
(dwLength == (6 * 2 * sizeof(WCHAR))))
{
guidValue.Data4[2] = (BYTE) ((uliValue.HighPart & 0x0000FF00) >> 8);
guidValue.Data4[3] = (BYTE) (uliValue.HighPart & 0x000000FF);
guidValue.Data4[4] = (BYTE) ((uliValue.LowPart & 0xFF000000) >> 24);
guidValue.Data4[5] = (BYTE) ((uliValue.LowPart & 0x00FF0000) >> 16);
guidValue.Data4[6] = (BYTE) ((uliValue.LowPart & 0x0000FF00) >> 8);
guidValue.Data4[7] = (BYTE) (uliValue.LowPart & 0x000000FF);
fStateChange = TRUE;
}
else
{
GuidParseState = Invalid;
}
break;
}
default:
{
GuidParseState = Invalid;
break;
}
} // end switch (on parse state)
//
// Move to next parse state (unless the string is bogus).
//
if (fStateChange)
{
fStateChange = FALSE;
uliValue.QuadPart = 0;
pwcStateStart = pwcCurrent + 1;
(*((int*) (&GuidParseState)))++;
}
break;
}
default:
{
GuidParseState = Invalid;
break;
}
} // end switch (on current character)
if (GuidParseState == Invalid)
{
break;
}
pwcCurrent++;
if ((pwcCurrent - m_pwszCurrentValue) > 38 * sizeof(WCHAR))
{
break;
}
} // end while (not at end of string)
//
// If we hit the end of the string when parsing the last element,
// we've succeeded. Commit the GUID.
//
if (GuidParseState == CloseBrace)
{
return pdp8aObject->SetElement( m_pwszCurrentKey, &guidValue, sizeof(GUID), DPNA_DATATYPE_GUID );
}
}
// If there are no NULLs it's probably a string
if( (
(dwDataType == DPNA_DATATYPE_STRING)
|| (dwDataType == 0xFFFFFFFF)
#ifndef DPNBUILD_ONLYONESP
|| (wcscmp(DPNA_KEY_PROVIDER,m_pwszCurrentKey)==0)
#endif // ! DPNBUILD_ONLYONESP
) &&
wcslen( m_pwszCurrentValue ) == m_dwValueLen )
{
// Otherwise it's a string
return pdp8aObject->SetElement( m_pwszCurrentKey, m_pwszCurrentValue, (wcslen(m_pwszCurrentValue)+1)*sizeof(WCHAR), DPNA_DATATYPE_STRING );
}
// Otherwise it's a binary (although the bytes were extended into WORDs/WCHARs.
return pdp8aObject->SetElement( m_pwszCurrentKey, m_pwszCurrentValue, (m_dwValueLen * sizeof(WCHAR)), DPNA_DATATYPE_BINARY );
}