/*========================================================================== * * 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 ); }