677 lines
14 KiB
C++
677 lines
14 KiB
C++
|
/*
|
||
|
|
||
|
Copyright (c) 1997-1999 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
sdpbstrl.cpp
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
|
||
|
Author:
|
||
|
|
||
|
*/
|
||
|
|
||
|
#include "sdppch.h"
|
||
|
|
||
|
#include "sdpbstrl.h"
|
||
|
|
||
|
#include <basetyps.h>
|
||
|
#include <oleauto.h>
|
||
|
#include <winsock2.h>
|
||
|
#include <wchar.h>
|
||
|
|
||
|
SDP_ARRAY_BSTR::~SDP_ARRAY_BSTR(
|
||
|
)
|
||
|
{
|
||
|
int Size = (int)GetSize();
|
||
|
|
||
|
if ( 0 < Size )
|
||
|
{
|
||
|
for ( int i=0; i < Size; i++ )
|
||
|
{
|
||
|
BSTR Member = GetAt(i);
|
||
|
|
||
|
ASSERT(NULL != Member);
|
||
|
if ( NULL == Member )
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
SysFreeString(Member);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
RemoveAll();
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
SDP_BSTRING::Reset(
|
||
|
)
|
||
|
{
|
||
|
// perform the destructor actions (freeing ptrs) and the constructor actions (initializing
|
||
|
// member variables to starting values)
|
||
|
|
||
|
// if there is a bstr, free it
|
||
|
if ( NULL != m_Bstr )
|
||
|
{
|
||
|
SysFreeString(m_Bstr);
|
||
|
}
|
||
|
|
||
|
m_Bstr = NULL;
|
||
|
m_CharacterSet = CS_UTF8;
|
||
|
m_CodePage = CP_UTF8;
|
||
|
|
||
|
// call the base class Reset
|
||
|
SDP_CHAR_STRING::Reset();
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
SDP_BSTRING::ConvertToBstr(
|
||
|
)
|
||
|
{
|
||
|
// ZoltanS bugfix:
|
||
|
// MutliByteToWideChar always fails if its input string is empty.
|
||
|
// Therefore, we must special-case a zero-length string.
|
||
|
|
||
|
DWORD dwOriginalLength = GetLength();
|
||
|
|
||
|
if ( 0 == dwOriginalLength )
|
||
|
{
|
||
|
// Shrink the member BSTR
|
||
|
if ( !SysReAllocStringLen(&m_Bstr, NULL, dwOriginalLength) )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// Make sure the member BSTR is emptied
|
||
|
m_Bstr[0] = L'\0';
|
||
|
|
||
|
}
|
||
|
else // we have a nonzero-length string to convert
|
||
|
{
|
||
|
// get the size of bstr needed to store the unicode representation
|
||
|
// cast the const char * returned from GetCharacterString to CHAR * because MultiByteToWideChar
|
||
|
// doesn't accept const char * (although thats what the parameter should be)
|
||
|
int BstrSize = MultiByteToWideChar(m_CodePage, 0, (CHAR *)GetCharacterString(),
|
||
|
dwOriginalLength, NULL, 0
|
||
|
);
|
||
|
|
||
|
// Check if the token can be converted to an appropriate bstr.
|
||
|
if (0 == BstrSize)
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// re-allocate bstr for the unicode representation
|
||
|
if ( !SysReAllocStringLen(&m_Bstr, NULL, BstrSize) )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// convert character string to bstr
|
||
|
// cast the const char * returned from GetCharacterString to CHAR * because MultiByteToWideChar
|
||
|
// doesn't accept const char * (although thats what the parameter should be)
|
||
|
if ( BstrSize != MultiByteToWideChar(
|
||
|
m_CodePage, 0, (CHAR *)GetCharacterString(),
|
||
|
dwOriginalLength, m_Bstr, BstrSize
|
||
|
) )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
SDP_BSTRING::GetBstr(
|
||
|
IN BSTR *pBstr
|
||
|
)
|
||
|
{
|
||
|
// ZoltanS
|
||
|
ASSERT( ! IsBadWritePtr(pBstr, sizeof(BSTR)) );
|
||
|
|
||
|
if ( !IsValid() )
|
||
|
{
|
||
|
return HRESULT_FROM_ERROR_CODE(ERROR_INVALID_DATA);
|
||
|
}
|
||
|
|
||
|
*pBstr = m_Bstr;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
SDP_BSTRING::GetBstrCopy(
|
||
|
IN BSTR * pBstr
|
||
|
)
|
||
|
{
|
||
|
// ZoltanS
|
||
|
if ( IsBadWritePtr(pBstr, sizeof(BSTR)) )
|
||
|
{
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
BSTR LocalPtr = NULL;
|
||
|
HRESULT HResult = GetBstr(&LocalPtr);
|
||
|
if ( FAILED(HResult) )
|
||
|
{
|
||
|
return HResult;
|
||
|
}
|
||
|
|
||
|
if ( (*pBstr = SysAllocString(LocalPtr)) == NULL )
|
||
|
{
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
SDP_BSTRING::SetBstr(
|
||
|
IN BSTR Bstr
|
||
|
)
|
||
|
{
|
||
|
if ( NULL == Bstr )
|
||
|
{
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
DWORD BstrLen = lstrlenW(Bstr);
|
||
|
BOOL DefaultUsed = FALSE;
|
||
|
|
||
|
// determine length of character string buffer
|
||
|
// If the codepage is UTF8 the last argument should be NULL
|
||
|
// if the caracterset is ASCII then we need to determine if the
|
||
|
// WideCharToMultiByte methods nneds replacment characters
|
||
|
|
||
|
int BufferSize = WideCharToMultiByte(
|
||
|
m_CodePage, 0, Bstr, BstrLen+1,
|
||
|
NULL, 0, NULL,
|
||
|
(m_CharacterSet == CS_ASCII ) ? &DefaultUsed : NULL
|
||
|
);
|
||
|
|
||
|
if ( 0 == BufferSize )
|
||
|
{
|
||
|
return HRESULT_FROM_ERROR_CODE(GetLastError());
|
||
|
}
|
||
|
|
||
|
if ( DefaultUsed )
|
||
|
{
|
||
|
return HRESULT_FROM_ERROR_CODE(SDP_INVALID_VALUE);
|
||
|
}
|
||
|
|
||
|
// now conversion cannot fail because the previous call made sure that
|
||
|
// the bstr can be converted to this multibyte string
|
||
|
// since failure is not possible, we do not need any code to restore
|
||
|
// the previous character string and it may be freed
|
||
|
if ( !ReAllocCharacterString(BufferSize) )
|
||
|
{
|
||
|
return HRESULT_FROM_ERROR_CODE(GetLastError());
|
||
|
}
|
||
|
|
||
|
// since the char string has been reallocated, the modifiable string must exist
|
||
|
// (i.e. the char string should not be by reference at this point)
|
||
|
ASSERT(NULL != GetModifiableCharString());
|
||
|
|
||
|
// convert to multibyte string
|
||
|
if ( BufferSize != WideCharToMultiByte(
|
||
|
m_CodePage, 0, Bstr, BstrLen+1,
|
||
|
GetModifiableCharString(), BufferSize, NULL, NULL
|
||
|
) )
|
||
|
{
|
||
|
ASSERT(FALSE);
|
||
|
return HRESULT_FROM_ERROR_CODE(GetLastError());
|
||
|
}
|
||
|
|
||
|
// reallocate memory and copy bstr
|
||
|
if ( !SysReAllocStringLen(&m_Bstr, Bstr, BstrLen) )
|
||
|
{
|
||
|
return HRESULT_FROM_ERROR_CODE(GetLastError());
|
||
|
}
|
||
|
|
||
|
IsValid(TRUE);
|
||
|
IsModified(TRUE);
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
SDP_BSTRING::InternalSetCharStrByRef(
|
||
|
IN CHAR *CharacterStringByReference,
|
||
|
IN DWORD Length
|
||
|
)
|
||
|
{
|
||
|
if ( !SDP_CHAR_STRING::InternalSetCharStrByRef(CharacterStringByReference, Length) )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if ( !ConvertToBstr() )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
SDP_BSTRING::InternalSetCharStrByCopy(
|
||
|
IN const CHAR *CharacterStringByCopy,
|
||
|
IN DWORD Length
|
||
|
)
|
||
|
{
|
||
|
if ( !SDP_CHAR_STRING::InternalSetCharStrByCopy(CharacterStringByCopy, Length) )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if ( !ConvertToBstr() )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
SDP_BSTRING::InternalParseToken(
|
||
|
IN CHAR *Token
|
||
|
)
|
||
|
{
|
||
|
UINT CodePage;
|
||
|
|
||
|
// parse the token using the base class parsing method
|
||
|
if ( !SDP_CHAR_STRING::InternalParseToken(Token) )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if ( !ConvertToBstr() )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
SDP_BSTRING::~SDP_BSTRING()
|
||
|
{
|
||
|
if ( NULL != m_Bstr )
|
||
|
{
|
||
|
SysFreeString(m_Bstr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void
|
||
|
SDP_OPTIONAL_BSTRING::Reset(
|
||
|
)
|
||
|
{
|
||
|
// perform the destructor actions (freeing ptrs) and the constructor actions (initializing
|
||
|
// member variables to starting values)
|
||
|
|
||
|
m_IsBstrCreated = FALSE;
|
||
|
|
||
|
// call the base class Reset
|
||
|
SDP_BSTRING::Reset();
|
||
|
}
|
||
|
|
||
|
|
||
|
// returns the bstr for the character string
|
||
|
// creates a bstr if required
|
||
|
HRESULT
|
||
|
SDP_OPTIONAL_BSTRING::GetBstr(
|
||
|
IN BSTR * pBstr
|
||
|
)
|
||
|
{
|
||
|
// ZoltanS
|
||
|
ASSERT( ! IsBadWritePtr(pBstr, sizeof(BSTR)) );
|
||
|
|
||
|
if ( !IsValid() )
|
||
|
{
|
||
|
return HRESULT_FROM_ERROR_CODE(ERROR_INVALID_DATA);
|
||
|
}
|
||
|
|
||
|
if ( !m_IsBstrCreated )
|
||
|
{
|
||
|
if ( !ConvertToBstr() )
|
||
|
{
|
||
|
return HRESULT_FROM_ERROR_CODE(GetLastError());
|
||
|
}
|
||
|
|
||
|
m_IsBstrCreated = TRUE;
|
||
|
}
|
||
|
|
||
|
*pBstr = m_Bstr;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
SDP_OPTIONAL_BSTRING::SetBstr(
|
||
|
IN BSTR Bstr
|
||
|
)
|
||
|
{
|
||
|
HRESULT HResult = SDP_BSTRING::SetBstr(Bstr);
|
||
|
if ( FAILED(HResult) )
|
||
|
{
|
||
|
return HResult;
|
||
|
}
|
||
|
|
||
|
m_IsBstrCreated = TRUE;
|
||
|
ASSERT(S_OK == HResult);
|
||
|
return HResult;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
SDP_OPTIONAL_BSTRING::InternalSetCharStrByRef(
|
||
|
IN CHAR *CharacterStringByReference,
|
||
|
IN DWORD Length
|
||
|
)
|
||
|
{
|
||
|
if ( !SDP_CHAR_STRING::InternalSetCharStrByRef(CharacterStringByReference, Length) )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
m_IsBstrCreated = FALSE;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
SDP_OPTIONAL_BSTRING::InternalSetCharStrByCopy(
|
||
|
IN const CHAR *CharacterStringByCopy,
|
||
|
IN DWORD Length
|
||
|
)
|
||
|
{
|
||
|
if ( !SDP_CHAR_STRING::InternalSetCharStrByCopy(CharacterStringByCopy, Length) )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
m_IsBstrCreated = FALSE;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
// since the bstr must only be created on demand, parsing must
|
||
|
// be over-ridden such that the bstr is not created during parsing
|
||
|
BOOL
|
||
|
SDP_OPTIONAL_BSTRING::InternalParseToken(
|
||
|
IN CHAR *Token
|
||
|
)
|
||
|
{
|
||
|
return SDP_CHAR_STRING::InternalParseToken(Token);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
SDP_BSTRING_LINE::GetBstrCopy(
|
||
|
IN BSTR *pBstr
|
||
|
)
|
||
|
{
|
||
|
// ZoltanS
|
||
|
if ( IsBadWritePtr(pBstr, sizeof(BSTR)) )
|
||
|
{
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
// if no elements in the field array, then the instance is invalid
|
||
|
if ( 0 >= m_FieldArray.GetSize() )
|
||
|
{
|
||
|
// ZoltanS fix: return a valid empty string! Otherwise we aren't
|
||
|
// conforming to Bstr semantics.
|
||
|
|
||
|
*pBstr = SysAllocString(L"");
|
||
|
|
||
|
if ( (*pBstr) == NULL )
|
||
|
{
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
return GetBstring().GetBstrCopy(pBstr);
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
SDP_BSTRING_LINE::SetBstr(
|
||
|
IN BSTR Bstr
|
||
|
)
|
||
|
{
|
||
|
BAIL_ON_FAILURE(GetBstring().SetBstr(Bstr));
|
||
|
|
||
|
try
|
||
|
{
|
||
|
// set the field and separator char array
|
||
|
m_FieldArray.SetAtGrow(0, &GetBstring());
|
||
|
m_SeparatorCharArray.SetAtGrow(0, CHAR_NEWLINE);
|
||
|
}
|
||
|
catch(...)
|
||
|
{
|
||
|
m_FieldArray.RemoveAll();
|
||
|
m_SeparatorCharArray.RemoveAll();
|
||
|
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
SDP_REQD_BSTRING_LINE::InternalReset(
|
||
|
)
|
||
|
{
|
||
|
m_Bstring.Reset();
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
SDP_CHAR_STRING_LINE::InternalReset(
|
||
|
)
|
||
|
{
|
||
|
m_SdpOptionalBstring.Reset();
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
SDP_LIMITED_CHAR_STRING::SetLimitedCharString(
|
||
|
IN CHAR *String
|
||
|
)
|
||
|
{
|
||
|
// check if the string is a legal string
|
||
|
// check if the token is one of the legal strings
|
||
|
for(UINT i=0; i < m_NumStrings; i++)
|
||
|
{
|
||
|
if ( !strcmp(m_LegalStrings[i], String) )
|
||
|
{
|
||
|
// parse the string using the base class parsing method
|
||
|
if ( !SDP_CHAR_STRING::InternalParseToken(String) )
|
||
|
{
|
||
|
return HRESULT_FROM_ERROR_CODE(GetLastError());
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// no matching legal string
|
||
|
return HRESULT_FROM_ERROR_CODE(ERROR_INVALID_DATA);
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
SDP_LIMITED_CHAR_STRING::InternalParseToken(
|
||
|
IN CHAR *Token
|
||
|
)
|
||
|
{
|
||
|
// check if the token is one of the legal strings
|
||
|
for(UINT i=0; i < m_NumStrings; i++)
|
||
|
{
|
||
|
if ( !strcmp(m_LegalStrings[i], Token) )
|
||
|
{
|
||
|
// parse the token using the base class parsing method
|
||
|
if ( !SDP_CHAR_STRING::InternalParseToken(Token) )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// the token does not match any of the legal strings
|
||
|
SetLastError(SDP_INVALID_FORMAT);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
SDP_ADDRESS::IsValidIP4Address(
|
||
|
IN CHAR *Address,
|
||
|
OUT ULONG &Ip4AddressValue
|
||
|
)
|
||
|
{
|
||
|
ASSERT(NULL != Address);
|
||
|
|
||
|
// check if there are atleast 3 CHAR_DOTs in the address string
|
||
|
// inet_addr accepts 3,2,1 or even no dots
|
||
|
CHAR *CurrentChar = Address;
|
||
|
BYTE NumDots = 0;
|
||
|
while (EOS != *CurrentChar)
|
||
|
{
|
||
|
if (CHAR_DOT == *CurrentChar)
|
||
|
{
|
||
|
NumDots++;
|
||
|
if (3 == NumDots)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// advance the ptr to the next char
|
||
|
CurrentChar++;
|
||
|
}
|
||
|
|
||
|
// check for the number of dots
|
||
|
if (3 != NumDots)
|
||
|
{
|
||
|
SetLastError(SDP_INVALID_ADDRESS);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// currently only ip4 is supported
|
||
|
Ip4AddressValue = inet_addr(Address);
|
||
|
|
||
|
// check if the address is a valid IP4 address
|
||
|
if ( (ULONG)INADDR_NONE == Ip4AddressValue )
|
||
|
{
|
||
|
SetLastError(SDP_INVALID_ADDRESS);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
SDP_ADDRESS::SetAddress(
|
||
|
IN BSTR Address
|
||
|
)
|
||
|
{
|
||
|
// SetBstr also sets the is modified and is valid flags on success
|
||
|
HRESULT ToReturn = SDP_OPTIONAL_BSTRING::SetBstr(Address);
|
||
|
if ( FAILED(ToReturn) )
|
||
|
{
|
||
|
return ToReturn;
|
||
|
}
|
||
|
|
||
|
// get the ip address
|
||
|
ULONG Ip4AddressValue;
|
||
|
|
||
|
// check if the token is a valid IP4 address
|
||
|
if ( !IsValidIP4Address(GetCharacterString(), Ip4AddressValue) )
|
||
|
{
|
||
|
IsModified(FALSE);
|
||
|
IsValid(FALSE);
|
||
|
return HRESULT_FROM_ERROR_CODE(GetLastError());
|
||
|
}
|
||
|
|
||
|
m_IsMulticastFlag = IN_MULTICAST(ntohl(Ip4AddressValue));
|
||
|
|
||
|
// the grammar requires that a multicast address be either an administratively scoped
|
||
|
// address "239.*" or out of the internet multicast conferencing range "224.2.*"
|
||
|
// we won't check that here as that may be overly restrictive
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
SDP_ADDRESS::SetBstr(
|
||
|
IN BSTR Bstr
|
||
|
)
|
||
|
{
|
||
|
return SetAddress(Bstr);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
SDP_ADDRESS::InternalParseToken(
|
||
|
IN CHAR *Token
|
||
|
)
|
||
|
{
|
||
|
ULONG Ip4AddressValue;
|
||
|
|
||
|
// check if the token is a valid IP4 address
|
||
|
if ( !IsValidIP4Address(Token, Ip4AddressValue) )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// check if the address(unicast or multicast) is same as whats expected
|
||
|
if ( IN_MULTICAST(ntohl(Ip4AddressValue)) != m_IsMulticastFlag )
|
||
|
{
|
||
|
SetLastError(SDP_INVALID_ADDRESS);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// the grammar requires that a multicast address be either an administratively scoped
|
||
|
// address "239.*" or out of the internet multicast conferencing range "224.2.*"
|
||
|
// we won't check that here as that may be overly restrictive
|
||
|
|
||
|
// call the base class parse token method
|
||
|
if ( !SDP_CHAR_STRING::InternalParseToken(Token) )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|