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

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