914 lines
23 KiB
C++
914 lines
23 KiB
C++
/*
|
|
|
|
Copyright (c) 1997-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
sdp.cpp
|
|
|
|
Abstract:
|
|
|
|
|
|
Author:
|
|
|
|
*/
|
|
#include "sdppch.h"
|
|
#include <strstrea.h>
|
|
|
|
#include "sdp.h"
|
|
#include "sdpstran.h"
|
|
|
|
|
|
|
|
// state transitions for each of the states
|
|
|
|
const STATE_TRANSITION g_StateStartTransitions[] = {
|
|
{CHAR_VERSION, STATE_VERSION}
|
|
};
|
|
|
|
const STATE_TRANSITION g_StateVersionTransitions[] = {
|
|
{CHAR_ORIGIN, STATE_ORIGIN}
|
|
};
|
|
|
|
const STATE_TRANSITION g_StateOriginTransitions[] = {
|
|
{CHAR_SESSION_NAME, STATE_SESSION_NAME}
|
|
};
|
|
|
|
const STATE_TRANSITION g_StateSessionNameTransitions[] = {
|
|
{CHAR_TITLE, STATE_TITLE},
|
|
{CHAR_URI, STATE_URI},
|
|
{CHAR_EMAIL, STATE_EMAIL},
|
|
{CHAR_PHONE, STATE_PHONE},
|
|
{CHAR_CONNECTION, STATE_CONNECTION}
|
|
};
|
|
|
|
const STATE_TRANSITION g_StateTitleTransitions[] = {
|
|
{CHAR_URI, STATE_URI},
|
|
{CHAR_EMAIL, STATE_EMAIL},
|
|
{CHAR_PHONE, STATE_PHONE},
|
|
{CHAR_CONNECTION, STATE_CONNECTION}
|
|
};
|
|
|
|
const STATE_TRANSITION g_StateUriTransitions[] = {
|
|
{CHAR_EMAIL, STATE_EMAIL},
|
|
{CHAR_PHONE, STATE_PHONE},
|
|
{CHAR_CONNECTION, STATE_CONNECTION}
|
|
};
|
|
|
|
const STATE_TRANSITION g_StateEmailTransitions[] = {
|
|
{CHAR_EMAIL, STATE_EMAIL},
|
|
{CHAR_PHONE, STATE_PHONE},
|
|
{CHAR_CONNECTION, STATE_CONNECTION}
|
|
};
|
|
|
|
const STATE_TRANSITION g_StatePhoneTransitions[] = {
|
|
{CHAR_PHONE, STATE_PHONE},
|
|
{CHAR_CONNECTION, STATE_CONNECTION}
|
|
};
|
|
|
|
const STATE_TRANSITION g_StateConnectionTransitions[] = {
|
|
{CHAR_BANDWIDTH, STATE_BANDWIDTH},
|
|
{CHAR_TIME, STATE_TIME},
|
|
{CHAR_KEY, STATE_KEY},
|
|
{CHAR_ATTRIBUTE, STATE_ATTRIBUTE},
|
|
{CHAR_MEDIA, STATE_MEDIA}
|
|
};
|
|
|
|
const STATE_TRANSITION g_StateBandwidthTransitions[] = {
|
|
{CHAR_TIME, STATE_TIME},
|
|
{CHAR_KEY, STATE_KEY},
|
|
{CHAR_ATTRIBUTE, STATE_ATTRIBUTE},
|
|
{CHAR_MEDIA, STATE_MEDIA}
|
|
};
|
|
|
|
const STATE_TRANSITION g_StateTimeTransitions[] = {
|
|
{CHAR_TIME, STATE_TIME},
|
|
{CHAR_REPEAT, STATE_REPEAT},
|
|
{CHAR_ADJUSTMENT, STATE_ADJUSTMENT},
|
|
{CHAR_KEY, STATE_KEY},
|
|
{CHAR_ATTRIBUTE, STATE_ATTRIBUTE},
|
|
{CHAR_MEDIA, STATE_MEDIA}
|
|
};
|
|
|
|
const STATE_TRANSITION g_StateRepeatTransitions[] = {
|
|
{CHAR_TIME, STATE_TIME},
|
|
{CHAR_REPEAT, STATE_REPEAT},
|
|
{CHAR_ADJUSTMENT, STATE_ADJUSTMENT},
|
|
{CHAR_KEY, STATE_KEY},
|
|
{CHAR_ATTRIBUTE, STATE_ATTRIBUTE},
|
|
{CHAR_MEDIA, STATE_MEDIA}
|
|
};
|
|
|
|
const STATE_TRANSITION g_StateAdjustmentTransitions[] = {
|
|
{CHAR_KEY, STATE_KEY},
|
|
{CHAR_ATTRIBUTE, STATE_ATTRIBUTE},
|
|
{CHAR_MEDIA, STATE_MEDIA}
|
|
};
|
|
|
|
const STATE_TRANSITION g_StateKeyTransitions[] = {
|
|
{CHAR_ATTRIBUTE, STATE_ATTRIBUTE},
|
|
{CHAR_MEDIA, STATE_MEDIA}
|
|
};
|
|
|
|
const STATE_TRANSITION g_StateAttributeTransitions[] = {
|
|
{CHAR_ATTRIBUTE, STATE_ATTRIBUTE},
|
|
{CHAR_MEDIA, STATE_MEDIA}
|
|
};
|
|
|
|
const STATE_TRANSITION g_StateMediaTransitions[] = {
|
|
{CHAR_MEDIA, STATE_MEDIA},
|
|
{CHAR_MEDIA_TITLE, STATE_MEDIA_TITLE},
|
|
{CHAR_MEDIA_CONNECTION, STATE_MEDIA_CONNECTION},
|
|
{CHAR_MEDIA_BANDWIDTH, STATE_MEDIA_BANDWIDTH},
|
|
{CHAR_MEDIA_KEY, STATE_MEDIA_KEY},
|
|
{CHAR_MEDIA_ATTRIBUTE, STATE_MEDIA_ATTRIBUTE}
|
|
};
|
|
|
|
const STATE_TRANSITION g_StateMediaTitleTransitions[] = {
|
|
{CHAR_MEDIA, STATE_MEDIA},
|
|
{CHAR_MEDIA_CONNECTION, STATE_MEDIA_CONNECTION},
|
|
{CHAR_MEDIA_BANDWIDTH, STATE_MEDIA_BANDWIDTH},
|
|
{CHAR_MEDIA_KEY, STATE_MEDIA_KEY},
|
|
{CHAR_MEDIA_ATTRIBUTE, STATE_MEDIA_ATTRIBUTE}
|
|
};
|
|
|
|
const STATE_TRANSITION g_StateMediaConnectionTransitions[]= {
|
|
{CHAR_MEDIA, STATE_MEDIA},
|
|
{CHAR_MEDIA_BANDWIDTH, STATE_MEDIA_BANDWIDTH},
|
|
{CHAR_MEDIA_KEY, STATE_MEDIA_KEY},
|
|
{CHAR_MEDIA_ATTRIBUTE, STATE_MEDIA_ATTRIBUTE}
|
|
};
|
|
|
|
const STATE_TRANSITION g_StateMediaBandwidthTransitions[]= {
|
|
{CHAR_MEDIA, STATE_MEDIA},
|
|
{CHAR_MEDIA_KEY, STATE_MEDIA_KEY},
|
|
{CHAR_MEDIA_ATTRIBUTE, STATE_MEDIA_ATTRIBUTE}
|
|
};
|
|
|
|
|
|
const STATE_TRANSITION g_StateMediaKeyTransitions[] = {
|
|
{CHAR_MEDIA, STATE_MEDIA},
|
|
{CHAR_MEDIA_ATTRIBUTE, STATE_MEDIA_ATTRIBUTE}
|
|
};
|
|
|
|
|
|
const STATE_TRANSITION g_StateMediaAttributeTransitions[]={
|
|
{CHAR_MEDIA, STATE_MEDIA},
|
|
{CHAR_MEDIA_ATTRIBUTE, STATE_MEDIA_ATTRIBUTE},
|
|
{CHAR_MEDIA, STATE_MEDIA}
|
|
};
|
|
|
|
|
|
// const state transition table definition
|
|
const TRANSITION_INFO g_TransitionTable[STATE_NUM_STATES] = {
|
|
STATE_TRANSITION_ENTRY(STATE_START, g_StateStartTransitions),
|
|
|
|
STATE_TRANSITION_ENTRY(STATE_VERSION, g_StateVersionTransitions),
|
|
|
|
STATE_TRANSITION_ENTRY(STATE_ORIGIN, g_StateOriginTransitions),
|
|
|
|
STATE_TRANSITION_ENTRY(STATE_SESSION_NAME, g_StateSessionNameTransitions),
|
|
|
|
STATE_TRANSITION_ENTRY(STATE_TITLE, g_StateTitleTransitions),
|
|
|
|
STATE_TRANSITION_ENTRY(STATE_URI, g_StateUriTransitions),
|
|
|
|
STATE_TRANSITION_ENTRY(STATE_EMAIL, g_StateEmailTransitions),
|
|
|
|
STATE_TRANSITION_ENTRY(STATE_PHONE, g_StatePhoneTransitions),
|
|
|
|
STATE_TRANSITION_ENTRY(STATE_CONNECTION, g_StateConnectionTransitions),
|
|
|
|
STATE_TRANSITION_ENTRY(STATE_BANDWIDTH, g_StateBandwidthTransitions),
|
|
|
|
STATE_TRANSITION_ENTRY(STATE_TIME, g_StateTimeTransitions),
|
|
|
|
STATE_TRANSITION_ENTRY(STATE_REPEAT, g_StateRepeatTransitions),
|
|
|
|
STATE_TRANSITION_ENTRY(STATE_ADJUSTMENT, g_StateAdjustmentTransitions),
|
|
|
|
STATE_TRANSITION_ENTRY(STATE_KEY, g_StateKeyTransitions),
|
|
|
|
STATE_TRANSITION_ENTRY(STATE_ATTRIBUTE, g_StateAttributeTransitions),
|
|
|
|
STATE_TRANSITION_ENTRY(STATE_MEDIA, g_StateMediaTransitions),
|
|
|
|
STATE_TRANSITION_ENTRY(STATE_MEDIA_TITLE, g_StateMediaTitleTransitions),
|
|
|
|
STATE_TRANSITION_ENTRY(STATE_MEDIA_CONNECTION, g_StateMediaConnectionTransitions),
|
|
|
|
STATE_TRANSITION_ENTRY(STATE_MEDIA_BANDWIDTH, g_StateMediaBandwidthTransitions),
|
|
|
|
STATE_TRANSITION_ENTRY(STATE_MEDIA_KEY, g_StateMediaKeyTransitions),
|
|
|
|
STATE_TRANSITION_ENTRY(STATE_MEDIA_ATTRIBUTE, g_StateMediaAttributeTransitions)
|
|
};
|
|
|
|
|
|
|
|
BOOL
|
|
SDP::Init(
|
|
)
|
|
{
|
|
// check if already initialized
|
|
if ( NULL != m_MediaList )
|
|
{
|
|
SetLastError(ERROR_ALREADY_INITIALIZED);
|
|
return FALSE;
|
|
}
|
|
|
|
// create media and time lists
|
|
// set flags to destroy them when the sdp instance destructs
|
|
|
|
try
|
|
{
|
|
m_MediaList = new SDP_MEDIA_LIST;
|
|
}
|
|
catch(...)
|
|
{
|
|
m_MediaList = NULL;
|
|
}
|
|
|
|
if ( NULL == m_MediaList )
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
m_DestroyMediaList = TRUE;
|
|
|
|
try
|
|
{
|
|
m_TimeList = new SDP_TIME_LIST;
|
|
}
|
|
catch(...)
|
|
{
|
|
m_TimeList = NULL;
|
|
}
|
|
|
|
if ( NULL == m_TimeList )
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
m_DestroyTimeList = TRUE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
// determine the character set implicit from the packet
|
|
BOOL
|
|
SDP::DetermineCharacterSet(
|
|
IN CHAR *SdpPacket,
|
|
OUT SDP_CHARACTER_SET &CharacterSet
|
|
)
|
|
{
|
|
ASSERT(NULL != SdpPacket);
|
|
|
|
// search for charset string (attribute "\na=charset:")
|
|
CHAR *AttributeString = strstr(SdpPacket, SDP_CHARACTER_SET_STRING);
|
|
|
|
// check if the character set is supplied
|
|
if ( NULL == AttributeString )
|
|
{
|
|
// ASCII is the default character set
|
|
CharacterSet = CS_ASCII;
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
// the character set attribute string must be present before the first media field
|
|
CHAR *FirstMediaField = strstr(SdpPacket, MEDIA_SEARCH_STRING);
|
|
|
|
// there is a media field and it doesn't occur after the character set string, signal error
|
|
if ( (NULL != FirstMediaField) &&
|
|
(FirstMediaField <= AttributeString) )
|
|
{
|
|
SetLastError(SDP_INVALID_CHARACTER_SET_FORMAT);
|
|
return FALSE;
|
|
}
|
|
|
|
// advance attribute string beyond the attribute specification
|
|
AttributeString += SDP_CHARACTER_SET_STRLEN;
|
|
|
|
// compare the character set string with each of the well known
|
|
// character set strings
|
|
for ( UINT i=0; i < NUM_SDP_CHARACTER_SET_ENTRIES; i++ )
|
|
{
|
|
// NOTE: no need to null terminate the character string as
|
|
// strncmp will return on finding the first character that
|
|
// doesn't match
|
|
if ( !strncmp(
|
|
AttributeString,
|
|
SDP_CHARACTER_SET_TABLE[i].m_CharSetString,
|
|
SDP_CHARACTER_SET_TABLE[i].m_Length
|
|
) )
|
|
{
|
|
CharacterSet = SDP_CHARACTER_SET_TABLE[i].m_CharSetCode;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
// unrecognized character set
|
|
SetLastError(SDP_INVALID_CHARACTER_SET);
|
|
return FALSE;
|
|
}
|
|
|
|
// the code should not reach here
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
Assumption: We are at the start of a new line. There may or may not be a
|
|
new line character before current
|
|
*/
|
|
|
|
BOOL
|
|
SDP::GetType(
|
|
OUT CHAR &Type,
|
|
OUT BOOL &EndOfPacket
|
|
)
|
|
{
|
|
// ensure that we don't peek beyond the end of the string
|
|
if ( EOS == m_Current[0] )
|
|
{
|
|
EndOfPacket = TRUE;
|
|
return TRUE;
|
|
}
|
|
|
|
// check if the second char is EQUAL_CHAR
|
|
if ( CHAR_EQUAL != m_Current[1] )
|
|
{
|
|
SetLastError(SDP_INVALID_FORMAT);
|
|
return FALSE;
|
|
}
|
|
|
|
EndOfPacket = FALSE;
|
|
Type = m_Current[0];
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SDP::CheckTransition(
|
|
IN CHAR Type,
|
|
IN PARSE_STATE CurrentParseState,
|
|
OUT PARSE_STATE &NewParseState
|
|
)
|
|
{
|
|
// validate the current state
|
|
ASSERT(STATE_NUM_STATES > CurrentParseState);
|
|
|
|
// validate transition table entry
|
|
ASSERT(g_TransitionTable[CurrentParseState].m_ParseState == CurrentParseState);
|
|
|
|
// see if such a trigger exists for the current state
|
|
for( UINT i=0; i < g_TransitionTable[CurrentParseState].m_NumTransitions; i++ )
|
|
{
|
|
// check if trigger has been found
|
|
if ( Type == g_TransitionTable[CurrentParseState].m_Transitions[i].m_Type )
|
|
{
|
|
NewParseState = g_TransitionTable[CurrentParseState].m_Transitions[i].m_NewParseState;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// check if a trigger was found
|
|
if ( g_TransitionTable[CurrentParseState].m_NumTransitions <= i )
|
|
{
|
|
SetLastError(SDP_INVALID_FORMAT);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SDP::GetValue(
|
|
IN CHAR Type
|
|
)
|
|
{
|
|
PARSE_STATE NewParseState;
|
|
|
|
// check if such a transition (current parse state --Type--> new parse state) exists
|
|
if ( !CheckTransition(Type, m_ParseState, NewParseState) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL LineParseResult = FALSE;
|
|
|
|
// fire corresponding action
|
|
switch(NewParseState)
|
|
{
|
|
case STATE_VERSION:
|
|
{
|
|
LineParseResult = m_ProtocolVersion.ParseLine(m_Current);
|
|
}
|
|
|
|
break;
|
|
|
|
case STATE_ORIGIN:
|
|
{
|
|
LineParseResult = m_Origin.ParseLine(m_Current);
|
|
}
|
|
|
|
break;
|
|
|
|
case STATE_SESSION_NAME:
|
|
{
|
|
LineParseResult = m_SessionName.ParseLine(m_Current);
|
|
}
|
|
|
|
break;
|
|
|
|
case STATE_TITLE:
|
|
{
|
|
LineParseResult = m_SessionTitle.ParseLine(m_Current);
|
|
}
|
|
|
|
break;
|
|
|
|
case STATE_URI:
|
|
{
|
|
LineParseResult = m_Uri.ParseLine(m_Current);
|
|
}
|
|
|
|
break;
|
|
|
|
case STATE_EMAIL:
|
|
{
|
|
LineParseResult = m_EmailList.ParseLine(m_Current);
|
|
}
|
|
|
|
break;
|
|
|
|
case STATE_PHONE:
|
|
{
|
|
LineParseResult = m_PhoneList.ParseLine(m_Current);
|
|
}
|
|
|
|
break;
|
|
|
|
case STATE_CONNECTION:
|
|
{
|
|
LineParseResult = m_Connection.ParseLine(m_Current);
|
|
}
|
|
|
|
break;
|
|
|
|
case STATE_BANDWIDTH:
|
|
{
|
|
LineParseResult = m_Bandwidth.ParseLine(m_Current);
|
|
}
|
|
|
|
break;
|
|
|
|
case STATE_TIME:
|
|
{
|
|
LineParseResult = GetTimeList().ParseLine(m_Current);
|
|
}
|
|
|
|
break;
|
|
|
|
case STATE_REPEAT:
|
|
{
|
|
ParseMember(SDP_TIME, GetTimeList(), SDP_REPEAT_LIST, GetRepeatList, m_Current, LineParseResult);
|
|
}
|
|
|
|
break;
|
|
|
|
case STATE_ADJUSTMENT:
|
|
{
|
|
LineParseResult = GetTimeList().GetAdjustment().ParseLine(m_Current);
|
|
}
|
|
|
|
break;
|
|
|
|
case STATE_KEY:
|
|
{
|
|
LineParseResult = m_EncryptionKey.ParseLine(m_Current);
|
|
}
|
|
|
|
break;
|
|
|
|
case STATE_ATTRIBUTE:
|
|
{
|
|
LineParseResult = m_AttributeList.ParseLine(m_Current);
|
|
}
|
|
|
|
break;
|
|
|
|
case STATE_MEDIA:
|
|
{
|
|
LineParseResult = GetMediaList().ParseLine(m_Current);
|
|
}
|
|
|
|
break;
|
|
|
|
case STATE_MEDIA_TITLE:
|
|
{
|
|
ParseMember(SDP_MEDIA, GetMediaList(), SDP_REQD_BSTRING_LINE, GetTitle, m_Current, LineParseResult);
|
|
}
|
|
|
|
break;
|
|
|
|
case STATE_MEDIA_CONNECTION:
|
|
{
|
|
ParseMember(SDP_MEDIA, GetMediaList(), SDP_CONNECTION, GetConnection, m_Current, LineParseResult);
|
|
}
|
|
|
|
break;
|
|
|
|
case STATE_MEDIA_BANDWIDTH:
|
|
{
|
|
ParseMember(SDP_MEDIA, GetMediaList(), SDP_BANDWIDTH, GetBandwidth, m_Current, LineParseResult);
|
|
}
|
|
|
|
break;
|
|
|
|
case STATE_MEDIA_KEY:
|
|
{
|
|
ParseMember(SDP_MEDIA, GetMediaList(), SDP_ENCRYPTION_KEY, GetEncryptionKey, m_Current, LineParseResult);
|
|
}
|
|
|
|
break;
|
|
|
|
case STATE_MEDIA_ATTRIBUTE:
|
|
{
|
|
ParseMember(SDP_MEDIA, GetMediaList(), SDP_ATTRIBUTE_LIST, GetAttributeList, m_Current, LineParseResult);
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
{
|
|
// should never reach here
|
|
ASSERT(FALSE);
|
|
|
|
SetLastError(SDP_INVALID_FORMAT);
|
|
return FALSE;
|
|
}
|
|
|
|
break;
|
|
};
|
|
|
|
// check if parsing the line succeeded
|
|
if ( !LineParseResult )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// change to the new state
|
|
m_ParseState = NewParseState;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
SDP::IsValidEndState(
|
|
) const
|
|
{
|
|
if ( (STATE_CONNECTION <= m_ParseState) &&
|
|
(STATE_NUM_STATES > m_ParseState) )
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
SetLastError(SDP_INVALID_FORMAT);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
void
|
|
SDP::Reset(
|
|
)
|
|
{
|
|
// perform the destructor actions (release any allocated resources)
|
|
|
|
// free the sdp packet if one was created
|
|
if ( NULL != m_SdpPacket )
|
|
{
|
|
delete m_SdpPacket;
|
|
m_SdpPacket = NULL;
|
|
}
|
|
|
|
// perform the constructor actions (initialize variables, resources)
|
|
|
|
// initialize the parse state
|
|
m_ParseState = STATE_START;
|
|
|
|
m_LastGenFailed = FALSE;
|
|
m_BytesAllocated = 0;
|
|
m_SdpPacketLength = 0;
|
|
|
|
m_Current = NULL;
|
|
m_ParseState = STATE_START;
|
|
|
|
// m_CharacterSet - nothing needs to be set
|
|
m_CharacterSet = CS_UTF8;
|
|
|
|
// reset the member instances
|
|
m_ProtocolVersion.Reset();
|
|
m_Origin.Reset();
|
|
m_SessionName.Reset();
|
|
m_SessionTitle.Reset();
|
|
m_Uri.Reset();
|
|
m_EmailList.Reset();
|
|
m_PhoneList.Reset();
|
|
m_Connection.Reset();
|
|
m_Bandwidth.Reset();
|
|
GetTimeList().Reset();
|
|
m_EncryptionKey.Reset();
|
|
m_AttributeList.Reset();
|
|
GetMediaList().Reset();
|
|
}
|
|
|
|
|
|
BOOL
|
|
SDP::ParseSdpPacket(
|
|
IN CHAR *SdpPacket,
|
|
IN SDP_CHARACTER_SET CharacterSet
|
|
)
|
|
{
|
|
ASSERT(NULL != m_MediaList);
|
|
ASSERT(NULL != m_TimeList);
|
|
|
|
// check if the instance has already parsed an sdp packet
|
|
if ( NULL != m_Current )
|
|
{
|
|
// reset the instance and try to parse the sdp packet
|
|
Reset();
|
|
}
|
|
|
|
// check if the passed in parameters are valid
|
|
if ( (NULL == SdpPacket) || (CS_INVALID == CharacterSet) )
|
|
{
|
|
SetLastError(SDP_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
// point the current pointer to the start of sdp packet
|
|
m_Current = SdpPacket;
|
|
|
|
// if the character set has not yet been determined
|
|
if ( CS_IMPLICIT == CharacterSet )
|
|
{
|
|
// determine the character set
|
|
if ( !DetermineCharacterSet(SdpPacket, m_CharacterSet) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
else // it cannot be CS_UNRECOGNIZED (checked on entry)
|
|
{
|
|
ASSERT(CS_INVALID != CharacterSet);
|
|
|
|
m_CharacterSet = CharacterSet;
|
|
}
|
|
|
|
// set the character sets for all the SDP_BSTRING instances that make up the SDP description
|
|
m_Origin.GetUserName().SetCharacterSet(m_CharacterSet);
|
|
m_SessionName.GetBstring().SetCharacterSet(m_CharacterSet);
|
|
m_SessionTitle.GetBstring().SetCharacterSet(m_CharacterSet);
|
|
|
|
m_EmailList.SetCharacterSet(m_CharacterSet);
|
|
m_PhoneList.SetCharacterSet(m_CharacterSet);
|
|
|
|
// set the character set for the SDP_MEDIA_LIST instance
|
|
GetMediaList().SetCharacterSet(m_CharacterSet);
|
|
|
|
// parse the type and its value for each line in the sdp packet
|
|
do
|
|
{
|
|
BOOL EndOfPacket;
|
|
CHAR Type;
|
|
|
|
// get the next type
|
|
if ( !GetType(Type, EndOfPacket) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if ( EndOfPacket )
|
|
{
|
|
break;
|
|
}
|
|
|
|
// advance the current pointer to beyond the Type= fields
|
|
m_Current+=2;
|
|
|
|
// get the value for the specified type
|
|
if ( !GetValue(Type) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
while ( 1 );
|
|
|
|
// validate if the parsing state is a valid end state
|
|
if ( !IsValidEndState() )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
// clears the modified state for each member field/value
|
|
// this is used in sdpblb.dll to clear the modified state (when an sdp
|
|
// is parsed in, the state of all parsed in fields/values is modified) and
|
|
// the m_WasModified dirty flag
|
|
void
|
|
SDP::ClearModifiedState(
|
|
)
|
|
{
|
|
m_ProtocolVersion.GetCharacterStringSize();
|
|
m_Origin.GetCharacterStringSize();
|
|
m_SessionName.GetCharacterStringSize();
|
|
m_SessionTitle.GetCharacterStringSize();
|
|
m_Uri.GetCharacterStringSize();
|
|
m_EmailList.GetCharacterStringSize();
|
|
m_PhoneList.GetCharacterStringSize();
|
|
m_Connection.GetCharacterStringSize();
|
|
m_Bandwidth.GetCharacterStringSize();
|
|
GetTimeList().GetCharacterStringSize();
|
|
m_EncryptionKey.GetCharacterStringSize();
|
|
m_AttributeList.GetCharacterStringSize();
|
|
GetMediaList().GetCharacterStringSize();
|
|
}
|
|
|
|
|
|
BOOL
|
|
SDP::IsValid(
|
|
)
|
|
{
|
|
// query only the mandatory values
|
|
return
|
|
m_ProtocolVersion.IsValid() &&
|
|
m_Origin.IsValid() &&
|
|
m_SessionName.IsValid() &&
|
|
m_Connection.IsValid();
|
|
}
|
|
|
|
|
|
BOOL
|
|
SDP::IsModified(
|
|
)
|
|
{
|
|
ASSERT(IsValid());
|
|
|
|
return
|
|
m_ProtocolVersion.IsModified() ||
|
|
m_Origin.IsModified() ||
|
|
m_SessionName.IsModified() ||
|
|
m_SessionTitle.IsModified() ||
|
|
m_Uri.IsModified() ||
|
|
m_EmailList.IsModified() ||
|
|
m_PhoneList.IsModified() ||
|
|
m_Connection.IsModified() ||
|
|
m_Bandwidth.IsModified() ||
|
|
GetTimeList().IsModified() ||
|
|
m_EncryptionKey.IsModified() ||
|
|
m_AttributeList.IsModified() ||
|
|
GetMediaList().IsModified();
|
|
}
|
|
|
|
|
|
// an sdp packet is not generated the way a line is generated (using a SeparatorChar and
|
|
// an sdp field carray). this is mainly because these carrays will have to be modified on
|
|
// insertion of email and phone lists, media fields and attribute lists or specification of
|
|
// other optional sdp properties.
|
|
|
|
CHAR *
|
|
SDP::GenerateSdpPacket(
|
|
)
|
|
{
|
|
// check if valid
|
|
if ( !IsValid() )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// check if the sdp packet needs to be regenerated
|
|
// (if the sdp packet exists and no modifications have taken place since
|
|
// the last time)
|
|
BOOL HasChangedSinceLast = IsModified();
|
|
if ( (!m_LastGenFailed) && (NULL != m_SdpPacket) && !HasChangedSinceLast )
|
|
{
|
|
return m_SdpPacket;
|
|
}
|
|
|
|
// determine the length of character string
|
|
m_SdpPacketLength =
|
|
m_ProtocolVersion.GetCharacterStringSize() +
|
|
m_Origin.GetCharacterStringSize() +
|
|
m_SessionName.GetCharacterStringSize() +
|
|
m_SessionTitle.GetCharacterStringSize() +
|
|
m_Uri.GetCharacterStringSize() +
|
|
m_EmailList.GetCharacterStringSize() +
|
|
m_PhoneList.GetCharacterStringSize() +
|
|
m_Connection.GetCharacterStringSize() +
|
|
m_Bandwidth.GetCharacterStringSize() +
|
|
GetTimeList().GetCharacterStringSize() +
|
|
m_EncryptionKey.GetCharacterStringSize() +
|
|
m_AttributeList.GetCharacterStringSize() +
|
|
GetMediaList().GetCharacterStringSize();
|
|
|
|
// check if a buffer needs to be allocated, allocate if required
|
|
if ( m_BytesAllocated < (m_SdpPacketLength+1) )
|
|
{
|
|
CHAR * NewSdpPacket;
|
|
|
|
try
|
|
{
|
|
NewSdpPacket = new CHAR[m_SdpPacketLength+1];
|
|
}
|
|
catch(...)
|
|
{
|
|
NewSdpPacket = NULL;
|
|
}
|
|
|
|
if (NewSdpPacket == NULL)
|
|
{
|
|
m_LastGenFailed = TRUE;
|
|
return NULL;
|
|
}
|
|
|
|
// if we have an old sdp packet, get rid of it now
|
|
if ( NULL != m_SdpPacket )
|
|
{
|
|
delete m_SdpPacket;
|
|
}
|
|
|
|
m_SdpPacket = NewSdpPacket;
|
|
m_BytesAllocated = m_SdpPacketLength+1;
|
|
}
|
|
|
|
// fill in the buffer
|
|
ostrstream OutputStream(m_SdpPacket, m_BytesAllocated);
|
|
|
|
// if this method ever fails here for this instance, further calls to the
|
|
// method without modification will return a ptr
|
|
if ( !( m_ProtocolVersion.PrintValue(OutputStream) &&
|
|
m_Origin.PrintValue(OutputStream) &&
|
|
m_SessionName.PrintValue(OutputStream) &&
|
|
m_SessionTitle.PrintValue(OutputStream) &&
|
|
m_Uri.PrintValue(OutputStream) &&
|
|
m_EmailList.PrintValue(OutputStream) &&
|
|
m_PhoneList.PrintValue(OutputStream) &&
|
|
m_Connection.PrintValue(OutputStream) &&
|
|
m_Bandwidth.PrintValue(OutputStream) &&
|
|
GetTimeList().PrintValue(OutputStream) &&
|
|
m_EncryptionKey.PrintValue(OutputStream) &&
|
|
m_AttributeList.PrintValue(OutputStream) &&
|
|
GetMediaList().PrintValue(OutputStream) )
|
|
)
|
|
{
|
|
m_LastGenFailed = TRUE;
|
|
return NULL;
|
|
}
|
|
|
|
OutputStream << EOS;
|
|
m_LastGenFailed = FALSE;
|
|
|
|
// dirty flag - is initially false and is set to TRUE when an sdp is generated because it had
|
|
// been modified since the last time the sdp was generated.
|
|
// NOTE: at this point IsModified() is false, so m_WasModified captures the fact that
|
|
// the sdp was modified at some point
|
|
if ( !m_WasModified && HasChangedSinceLast )
|
|
{
|
|
m_WasModified = TRUE;
|
|
}
|
|
return m_SdpPacket;
|
|
}
|
|
|
|
|
|
|
|
SDP::~SDP(
|
|
)
|
|
{
|
|
if ( NULL != m_SdpPacket )
|
|
{
|
|
delete m_SdpPacket;
|
|
}
|
|
|
|
if ( m_DestroyMediaList && (NULL != m_MediaList) )
|
|
{
|
|
delete m_MediaList;
|
|
}
|
|
|
|
if ( m_DestroyTimeList && (NULL != m_TimeList) )
|
|
{
|
|
delete m_TimeList;
|
|
}
|
|
}
|