windows-nt/Source/XPSP1/NT/net/tapi/skywalker/parser/sdpbstrl.cpp
2020-09-26 16:20:57 +08:00

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;
}