609 lines
13 KiB
C++
609 lines
13 KiB
C++
/*==========================================================================
|
|
*
|
|
* Copyright (C) 2000 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 )
|
|
{
|
|
delete [] m_pwszCurrentKey;
|
|
}
|
|
|
|
if( m_pwszCurrentValue != NULL )
|
|
{
|
|
delete [] m_pwszCurrentValue;
|
|
}
|
|
|
|
if ( m_pbUserData != NULL )
|
|
{
|
|
delete [] m_pbUserData;
|
|
}
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DP8ADDRESSPARSE::ParseURL"
|
|
HRESULT DP8ADDRESSPARSE::ParseURL( DP8ADDRESSOBJECT *dp8aObject, WCHAR *pstrURL )
|
|
{
|
|
HRESULT hr;
|
|
|
|
if( m_pwszCurrentKey != NULL )
|
|
{
|
|
delete [] m_pwszCurrentKey;
|
|
m_pwszCurrentKey = NULL;
|
|
}
|
|
|
|
if( m_pwszCurrentValue != NULL )
|
|
{
|
|
delete [] m_pwszCurrentValue;
|
|
m_pwszCurrentValue = NULL;
|
|
}
|
|
|
|
if( m_pbUserData != NULL )
|
|
{
|
|
delete [] 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 = new WCHAR[m_dwLenURL+1];
|
|
if( !m_pwszCurrentKey )
|
|
{
|
|
DPFX(DPFPREP, 0, "Error allocating memory" );
|
|
return DPNERR_OUTOFMEMORY;
|
|
}
|
|
m_pwszCurrentValue = new WCHAR[m_dwLenURL+1];
|
|
if( !m_pwszCurrentValue )
|
|
{
|
|
delete [] m_pwszCurrentKey;
|
|
m_pwszCurrentKey = NULL;
|
|
DPFX(DPFPREP, 0, "Error allocating memory" );
|
|
return DPNERR_OUTOFMEMORY;
|
|
}
|
|
m_pbUserData = new BYTE[m_dwLenURL+1];
|
|
if( !m_pbUserData )
|
|
{
|
|
delete [] m_pwszCurrentKey;
|
|
delete [] 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( 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( szBaseStrings[dwIndex], m_pwszCurrentKey ) == 0 )
|
|
{
|
|
dwDataType = dwBaseRequiredTypes[dwIndex] ;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If it's numeric
|
|
if( (dwDataType == DPNA_DATATYPE_DWORD || dwDataType == 0xFFFFFFFF) && !m_fNonNumeric && wcslen(m_pwszCurrentValue)<=10)
|
|
{
|
|
DWORD dwTmpValue;
|
|
|
|
dwTmpValue = _wtol( m_pwszCurrentValue );
|
|
|
|
return pdp8aObject->SetElement( m_pwszCurrentKey, &dwTmpValue, sizeof(DWORD), DPNA_DATATYPE_DWORD );
|
|
}
|
|
|
|
UINT aiTmp[11];
|
|
|
|
// We've read a GUID
|
|
if( (dwDataType == DPNA_DATATYPE_GUID || dwDataType == 0xFFFFFFFF) && wcslen( m_pwszCurrentValue ) == 38 && swscanf( m_pwszCurrentValue, L"{%8X-%4X-%4X-%2X%2X-%2X%2X%2X%2X%2X%2X}" ,
|
|
&aiTmp[0],
|
|
&aiTmp[1], &aiTmp[2],
|
|
&aiTmp[3], &aiTmp[4],
|
|
&aiTmp[5], &aiTmp[6],
|
|
&aiTmp[7], &aiTmp[8],
|
|
&aiTmp[9], &aiTmp[10]) == 11)
|
|
{
|
|
GUID guidValue;
|
|
|
|
guidValue.Data1 = (ULONG) aiTmp[0];
|
|
guidValue.Data2 = (USHORT) aiTmp[1];
|
|
guidValue.Data3 = (USHORT) aiTmp[2];
|
|
guidValue.Data4[0] = (BYTE) aiTmp[3];
|
|
guidValue.Data4[1] = (BYTE) aiTmp[4];
|
|
guidValue.Data4[2] = (BYTE) aiTmp[5];
|
|
guidValue.Data4[3] = (BYTE) aiTmp[6];
|
|
guidValue.Data4[4] = (BYTE) aiTmp[7];
|
|
guidValue.Data4[5] = (BYTE) aiTmp[8];
|
|
guidValue.Data4[6] = (BYTE) aiTmp[9];
|
|
guidValue.Data4[7] = (BYTE) aiTmp[10];
|
|
|
|
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 || wcscmp(DPNA_KEY_PROVIDER,m_pwszCurrentKey)==0 ) && 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 );
|
|
|
|
}
|
|
|
|
|
|
|