415 lines
9.8 KiB
C++
415 lines
9.8 KiB
C++
|
/*
|
||
|
|
||
|
Copyright (c) 1997-1999 Microsoft Corporation
|
||
|
|
||
|
*/
|
||
|
|
||
|
#include "sdppch.h"
|
||
|
|
||
|
#include <strstrea.h>
|
||
|
|
||
|
#include "sdpgen.h"
|
||
|
#include "sdpfld.h"
|
||
|
#include "sdpval.h"
|
||
|
#include "sdpltran.h"
|
||
|
|
||
|
|
||
|
|
||
|
// check if each of the fields in the field array is valid
|
||
|
BOOL
|
||
|
SDP_VALUE::IsValid(
|
||
|
) const
|
||
|
{
|
||
|
// if there are no members in the field array, then the instance is invalid
|
||
|
int NumFields = (int)m_FieldArray.GetSize();
|
||
|
if ( 0 >= NumFields )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// check each of the members in the list for validity
|
||
|
for (int i = 0; i < NumFields; i++)
|
||
|
{
|
||
|
SDP_FIELD *Field = m_FieldArray[i];
|
||
|
|
||
|
// only the last field can be null
|
||
|
ASSERT((i >= (NumFields-1)) || (NULL != Field));
|
||
|
|
||
|
if ( NULL != Field )
|
||
|
{
|
||
|
// if even one member is invalid, return FALSE
|
||
|
if ( !Field->IsValid() )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// all members are valid
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
SDP_VALUE::CalcIsModified(
|
||
|
) const
|
||
|
{
|
||
|
ASSERT(IsValid());
|
||
|
|
||
|
int NumFields = (int)m_FieldArray.GetSize();
|
||
|
for (int i = 0; i < NumFields; i++)
|
||
|
{
|
||
|
SDP_FIELD *Field = m_FieldArray[i];
|
||
|
|
||
|
// only the last field can be null
|
||
|
ASSERT((i >= (NumFields-1)) || (NULL != Field));
|
||
|
|
||
|
if ( (NULL != Field) && Field->IsModified() )
|
||
|
{
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
SDP_VALUE::CalcCharacterStringSize(
|
||
|
)
|
||
|
{
|
||
|
ASSERT(IsValid());
|
||
|
|
||
|
// since the cost of checking if any of the constituent fields have
|
||
|
// changed since last time is almost as much as actually computing the size,
|
||
|
// the size is computed afresh each time this method is called
|
||
|
DWORD m_CharacterStringSize = 0;
|
||
|
|
||
|
int NumFields = (int)m_FieldArray.GetSize();
|
||
|
for (int i = 0; i < NumFields; i++)
|
||
|
{
|
||
|
SDP_FIELD *Field = m_FieldArray[i];
|
||
|
|
||
|
// only the last field can be null
|
||
|
ASSERT((i >= (NumFields-1)) || (NULL != Field));
|
||
|
|
||
|
if ( NULL != Field )
|
||
|
{
|
||
|
// add field string length
|
||
|
m_CharacterStringSize += Field->GetCharacterStringSize();
|
||
|
}
|
||
|
|
||
|
// add separator character length
|
||
|
m_CharacterStringSize++;
|
||
|
}
|
||
|
|
||
|
// if there is a line, add the prefix string length
|
||
|
if ( 0 < NumFields )
|
||
|
{
|
||
|
m_CharacterStringSize += strlen( m_TypePrefixString );
|
||
|
}
|
||
|
|
||
|
return m_CharacterStringSize;
|
||
|
}
|
||
|
|
||
|
|
||
|
// this method should only be called after having called GetCharacterStringSize()
|
||
|
// should only be called if valid
|
||
|
BOOL
|
||
|
SDP_VALUE::CopyValue(
|
||
|
OUT ostrstream &OutputStream
|
||
|
)
|
||
|
{
|
||
|
// should be valid
|
||
|
ASSERT(IsValid());
|
||
|
|
||
|
// copy the prefix onto the buffer ptr
|
||
|
OutputStream << (CHAR *)m_TypePrefixString;
|
||
|
if ( OutputStream.fail() )
|
||
|
{
|
||
|
SetLastError(SDP_OUTPUT_ERROR);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
int NumFields = (int)m_FieldArray.GetSize();
|
||
|
|
||
|
// the assumption here is that atleast one field must have been parsed in
|
||
|
// if the value is valid
|
||
|
ASSERT(0 != NumFields);
|
||
|
|
||
|
for (int i = 0; i < NumFields; i++)
|
||
|
{
|
||
|
SDP_FIELD *Field = m_FieldArray[i];
|
||
|
|
||
|
// only the last field can be null
|
||
|
ASSERT((i >= (NumFields-1)) || (NULL != Field));
|
||
|
|
||
|
if ( NULL != Field )
|
||
|
{
|
||
|
if ( !Field->PrintField(OutputStream) )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
OutputStream << m_SeparatorCharArray[i];
|
||
|
}
|
||
|
|
||
|
// newline is presumably the last character parsed and entered into the array
|
||
|
ASSERT(CHAR_NEWLINE == m_SeparatorCharArray[i-1]);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
SDP_VALUE::InternalParseLine(
|
||
|
IN OUT CHAR *&Line
|
||
|
)
|
||
|
{
|
||
|
ASSERT(NULL != m_SdpLineTransition);
|
||
|
|
||
|
BOOL Finished;
|
||
|
|
||
|
// parse fields until there are no more fields to parse or an error occurs
|
||
|
do
|
||
|
{
|
||
|
// check if the line state value is consistent with the corresponding entry
|
||
|
const LINE_TRANSITION_INFO * const LineTransitionInfo =
|
||
|
m_SdpLineTransition->GetAt(m_LineState);
|
||
|
|
||
|
if ( NULL == LineTransitionInfo )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
CHAR SeparatorChar = '\0';
|
||
|
SDP_FIELD *Field;
|
||
|
CHAR *SeparatorString;
|
||
|
|
||
|
// identify the token. if one of the the separator characters is found, replace
|
||
|
// it by EOS and return the separator char. if none of the separator characters are
|
||
|
// found, return NULL (ex. if EOS found first, return NULL)
|
||
|
CHAR *Token = GetToken(
|
||
|
Line,
|
||
|
LineTransitionInfo->m_NumTransitions,
|
||
|
LineTransitionInfo->m_SeparatorChars,
|
||
|
SeparatorChar
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Eliminate also the '\r'
|
||
|
// from the token
|
||
|
//
|
||
|
if( Token )
|
||
|
{
|
||
|
int nStrLen = strlen( Token );
|
||
|
for( int c = 0; c < nStrLen; c++)
|
||
|
{
|
||
|
CHAR& chElement = Token[c];
|
||
|
if( chElement == '\r' )
|
||
|
{
|
||
|
chElement = '\0';
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// when the block goes out of scope,
|
||
|
// set the EOS character to the token separator character
|
||
|
LINE_TERMINATOR LineTerminator(Token, SeparatorChar);
|
||
|
|
||
|
// if there is no such token
|
||
|
if ( !LineTerminator.IsLegal() )
|
||
|
{
|
||
|
SetLastError(m_ErrorCode);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// advance the line to the start of the next token
|
||
|
Line += (LineTerminator.GetLength() + 1);
|
||
|
|
||
|
BOOL AddToArray;
|
||
|
|
||
|
// check if there was such a state transition
|
||
|
// it returns a field if it needs to be parsed and a separate
|
||
|
// finished flag to indicate end of line parsing
|
||
|
if ( !GetFieldToParse(SeparatorChar, LineTransitionInfo, Field, Finished, AddToArray) )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// add the separator character and the field to the array
|
||
|
if ( AddToArray )
|
||
|
{
|
||
|
ASSERT(m_FieldArray.GetSize() == m_SeparatorCharArray.GetSize());
|
||
|
|
||
|
INT_PTR Index;
|
||
|
|
||
|
try
|
||
|
{
|
||
|
Index = m_SeparatorCharArray.Add(SeparatorChar);
|
||
|
}
|
||
|
catch(...)
|
||
|
{
|
||
|
SetLastError(ERROR_OUTOFMEMORY);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
try
|
||
|
{
|
||
|
m_FieldArray.Add(Field);
|
||
|
}
|
||
|
catch(...)
|
||
|
{
|
||
|
m_SeparatorCharArray.RemoveAt(Index);
|
||
|
|
||
|
SetLastError(ERROR_OUTOFMEMORY);
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// check if any more fields need to be parsed
|
||
|
if ( NULL == Field )
|
||
|
{
|
||
|
ASSERT(TRUE == Finished);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// parse the field
|
||
|
if ( !Field->ParseToken(Token) )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
while (!Finished);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
SDP_VALUE::GetFieldToParse(
|
||
|
IN const CHAR SeparatorChar,
|
||
|
IN const LINE_TRANSITION_INFO *LineTransitionInfo,
|
||
|
OUT SDP_FIELD *&Field,
|
||
|
OUT BOOL &Finished,
|
||
|
OUT BOOL &AddToArray
|
||
|
)
|
||
|
{
|
||
|
// no need for an if ( NULL != ...) because the caller ParseLine method must have verified
|
||
|
// this before calling this method
|
||
|
ASSERT(NULL != LineTransitionInfo);
|
||
|
|
||
|
const LINE_TRANSITION * const LineTransitions = LineTransitionInfo->m_Transitions;
|
||
|
|
||
|
if ( NULL == LineTransitions )
|
||
|
{
|
||
|
SetLastError(SDP_INTERNAL_ERROR);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// check if there is such a triggering separator
|
||
|
for( UINT i=0; i < LineTransitionInfo->m_NumTransitions; i++ )
|
||
|
{
|
||
|
// check the separator for the transition
|
||
|
if ( SeparatorChar == LineTransitions[i].m_SeparatorChar )
|
||
|
{
|
||
|
// perform the state transition - this is needed to determine the field to
|
||
|
// parse. ideally the transition should occur after the action (ParseField),
|
||
|
// but it doesn't matter here
|
||
|
m_LineState = LineTransitions[i].m_NewLineState;
|
||
|
|
||
|
// check if this transition was only meant to consume the separator character
|
||
|
// and no fields need to be parsed
|
||
|
if ( LINE_END == m_LineState )
|
||
|
{
|
||
|
// currently only a newline brings the state to LINE_END
|
||
|
ASSERT(CHAR_NEWLINE == SeparatorChar);
|
||
|
|
||
|
Field = NULL;
|
||
|
Finished = TRUE;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
// get the field to parse for the current state
|
||
|
if ( !GetField(Field, AddToArray) )
|
||
|
{
|
||
|
ASSERT(FALSE);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// if the separator character was a newline, we are finished
|
||
|
Finished = (CHAR_NEWLINE == SeparatorChar)? TRUE: FALSE;
|
||
|
|
||
|
// success
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// no valid transition for the separator
|
||
|
SetLastError(m_ErrorCode);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
SDP_VALUE_LIST::IsModified(
|
||
|
) const
|
||
|
{
|
||
|
int NumElements = (int)GetSize();
|
||
|
|
||
|
for ( int i = 0; i < NumElements; i++ )
|
||
|
{
|
||
|
if ( GetAt(i)->IsModified() )
|
||
|
{
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
SDP_VALUE_LIST::GetCharacterStringSize(
|
||
|
)
|
||
|
{
|
||
|
DWORD ReturnValue = 0;
|
||
|
int NumElements = (int)GetSize();
|
||
|
|
||
|
for ( int i = 0; i < NumElements; i++ )
|
||
|
{
|
||
|
ReturnValue += GetAt(i)->GetCharacterStringSize();
|
||
|
}
|
||
|
|
||
|
return ReturnValue;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
SDP_VALUE_LIST::PrintValue(
|
||
|
OUT ostrstream &OutputStream
|
||
|
)
|
||
|
{
|
||
|
// should not be modified
|
||
|
ASSERT(!IsModified());
|
||
|
|
||
|
int NumElements = (int)GetSize();
|
||
|
|
||
|
for ( int i = 0; i < NumElements; i++ )
|
||
|
{
|
||
|
if ( !GetAt(i)->PrintValue(OutputStream) )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|