in FixAntenna/NetCore/FixEngine/Transport/FixMessageChopper.cs [177:584]
public void ReadMessage(MsgBuf buf)
{
var message = buf.FixMessage;
if (message == null)
{
message = new FixMessage();
buf.FixMessage = message;
}
if (_parsedOffset == _readOffset)
{
if (_readOffset <= _optimalBufferObj.Length)
{
_buffer = _optimalBufferObj.GetByteArray();
_bufferObj = _optimalBufferObj;
}
_parsedOffset = _readOffset = 0;
}
_messageStartOffset = _parsedOffset;
var offsetLimit = _messageStartOffset + _maxMessageSize;
var parsedBodyLength = 0;
var checksum = 0;
var parsedChecksum = 0;
var parsedChecksumBytes = 0;
_isGarbled = false;
var valueStartIndex = 0;
var valueOffset = 0;
var tag = 0;
var isTagParsing = true;
var userStopParse = false;
var isHeaderTag = true;
var isAdminMsg = false;
message.SetBuffer(_buffer, _messageStartOffset, _readOffset);
MoveToNextStepAndSetResetOffset(GarbledMessageError.Field8TagExpected);
ResetState();
OnMessageStart();
do
{
if (_messageStartOffset != _parsedOffset)
{ // if we read something from transport
if (_readOffset <= _optimalBufferLength || _messageStartOffset == 0)
{
message.SetBuffer(_buffer, _messageStartOffset, _readOffset);
}
else
{
// end of buffer reached, wrap around now and move remaining data to buffer's head
Array.Copy(_buffer, _messageStartOffset, _buffer, 0, _readOffset - _messageStartOffset);
_readOffset -= _messageStartOffset;
_parsedOffset -= _messageStartOffset;
valueStartIndex -= _messageStartOffset;
valueOffset -= _messageStartOffset;
_messageStartOffset = 0;
message.ShiftBuffer(_buffer, _messageStartOffset, _readOffset);
}
offsetLimit = _messageStartOffset + _maxMessageSize;
}
while (_parsedOffset < _readOffset)
{
// Check message size
if (_checkMessageSize && _parsedOffset >= offsetLimit)
{
GetMessage(buf);
throw new GarbledMessageException(MessageChopperFields.MessageIsTooLongError + " (maxMessageSize=" + _maxMessageSize + ")");
}
var ch = (char) _buffer[_parsedOffset];
if (!_isGarbled)
{
if (isTagParsing)
{
if (ch >= '0' && ch <= '9')
{
tag = tag * 10 + (ch - '0');
}
else if (ch == '=')
{
if (RawTags.IsWithinRawTags(tag))
{
var rawLength = 0;
if (message.IsMessageIncomplete)
{
byte bv;
for (var i = valueStartIndex; i < _parsedOffset; i++)
{
bv = _buffer[i];
if (bv >= '0' && bv <= '9')
{
rawLength = rawLength * 10 + (bv - '0');
}
else if (bv == '\u0001')
{
break;
}
}
}
else
{
rawLength = RawFixUtil.GetRawTagLengthFromPreviousField(message);
}
if (rawLength > offsetLimit)
{
throw new GarbledMessageException(MessageChopperFields.RawDataLengthIsTooBigError + " (" + rawLength + ")");
}
valueOffset = _parsedOffset + rawLength;
}
valueStartIndex = _parsedOffset + 1;
isTagParsing = false;
}
else
{
ResetStateAndGetResetOffset();
}
}
else
{
if (ch == '\x0001')
{
// check if not in raw data
if (_parsedOffset > valueOffset)
{
if (_isAdvancedParseControl)
{
if (userStopParse)
{
if (isHeaderTag)
{
if (ParseRequiredTags.IsHeader(tag))
{
message.Add(tag, valueStartIndex, _parsedOffset - valueStartIndex);
}
else
{
message.LoadTagValue(35, _tempValue);
isAdminMsg = ParseRequiredTags.IsAdminMsg(_tempValue);
isHeaderTag = false;
if (isAdminMsg)
{
message.Add(tag, valueStartIndex, _parsedOffset - valueStartIndex);
}
}
}
else if (isAdminMsg)
{
message.Add(tag, valueStartIndex, _parsedOffset - valueStartIndex);
}
else if (ParseRequiredTags.IsTrailer(tag))
{
message.Add(tag, valueStartIndex, _parsedOffset - valueStartIndex);
}
}
else
{
var control = _parserListener.OnTag(tag, _buffer, valueStartIndex, _parsedOffset - valueStartIndex);
if (control == FixParserListenerParseControl.Continue)
{
message.Add(tag, valueStartIndex, _parsedOffset - valueStartIndex);
}
else
{
// IGNORE or STOP
if (ParseRequiredTags.IsRequired(tag))
{
message.Add(tag, valueStartIndex, _parsedOffset - valueStartIndex);
}
else
{
message.IsMessageIncomplete = true;
}
if (control == FixParserListenerParseControl.StopParse)
{
userStopParse = true;
}
}
}
}
else
{
message.Add(tag, valueStartIndex, _parsedOffset - valueStartIndex);
}
tag = 0;
isTagParsing = true;
}
}
}
}
switch (_state)
{
case 0:
checksum += ch;
if (ch == '8')
{
if (AreThereParsedDataInBuffer())
{
// Before analise new message flush the buffered data (garbled message)
goto loopBreak;
}
else
{
MoveToNextStepAndSetResetOffset(GarbledMessageError.Field8TagValueDelimiterExpected);
}
}
else
{
_isGarbled = true;
ResetState();
}
break;
case 1:
checksum += ch;
if (ch == '=')
{
MoveToNextStepAndSetResetOffset(GarbledMessageError.Field8FieldDelimiterExpected);
}
else
{
ResetStateAndGetResetOffset();
}
break;
case 2:
checksum += ch;
if (ch == '\x0001')
{
MoveToNextStepAndSetResetOffset(GarbledMessageError.Field9TagExpected);
}
else if (ch == '8')
{
ResetStateAndGetResetOffset();
}
break;
case 3:
checksum += ch;
if (ch == '9')
{
MoveToNextStepAndSetResetOffset(GarbledMessageError.Field9TagValueDelimiterExpected);
}
else
{
ResetStateAndGetResetOffset();
}
break;
case 4:
checksum += ch;
if (ch == '=')
{
MoveToNextStepAndSetResetOffset(GarbledMessageError.Field9DecimalValueExpected);
}
else
{
ResetStateAndGetResetOffset();
}
break;
case 5:
checksum += ch;
if (ch >= '0' && ch <= '9')
{
parsedBodyLength = parsedBodyLength * 10 + (ch - '0');
}
else if (ch == '\x0001' && parsedBodyLength != 0)
{
MoveToNextStepAndSetResetOffset(GarbledMessageError.Field35TagExpected);
}
else
{
ResetStateAndGetResetOffset();
}
break;
case 6:
checksum += ch;
--parsedBodyLength;
if (ch == '3')
{
MoveToNextState(GarbledMessageError.Field35TagExpected);
}
else
{
ResetStateAndGetResetOffset();
}
break;
case 7:
checksum += ch;
--parsedBodyLength;
if (ch == '5')
{
MoveToNextState(GarbledMessageError.Field35TagValueDelimiterExpected);
}
else
{
ResetStateAndGetResetOffset();
}
break;
case 8:
checksum += ch;
--parsedBodyLength;
if (ch == '=')
{
MoveToNextState(GarbledMessageError.Field35FieldDelimiterExpected);
}
else
{
ResetStateAndGetResetOffset();
}
break;
case 9:
checksum += ch;
--parsedBodyLength;
if (ch == '\x0001')
{
MoveToNextState(GarbledMessageError.InvalidTagNumber);
if (parsedBodyLength <= 0)
{
MoveToNextState(GarbledMessageError.Field10TagExpected);
}
}
break;
case 10:
checksum += ch;
--parsedBodyLength;
if (parsedBodyLength <= 0)
{
MoveToNextState(GarbledMessageError.Field10TagExpected);
}
break;
case 11:
if (ch == '1')
{
checksum &= 255;
MoveToNextState(GarbledMessageError.Field10TagExpected);
}
else
{
ResetStateAndGetResetOffset();
}
break;
case 12:
if (ch == '0')
{
MoveToNextState(GarbledMessageError.Field10TagValueDelimiterExpected);
}
else
{
ResetStateAndGetResetOffset();
}
break;
case 13:
if (ch == '=')
{
MoveToNextState(GarbledMessageError.Field10DecimalValueExpected);
}
else
{
ResetStateAndGetResetOffset();
}
break;
case 14:
if (ch >= '0' && ch <= '9')
{
parsedChecksum = parsedChecksum * 10 + (ch - '0');
if (++parsedChecksumBytes == 3)
{
MoveToNextState(GarbledMessageError.Field10FieldDelimiterExpected);
}
}
else
{
ResetStateAndGetResetOffset();
}
break;
case 15:
if (ch == '\x0001')
{
_parsedOffset++;
MoveToNextState(GarbledMessageError.Field10InvalidChecksum);
if (!_validateCheckSum || checksum == parsedChecksum)
{
MoveToNextState(null);
}
else
{
_isGarbled = true;
ResetState();
}
goto loopBreak;
}
else
{
ResetStateAndGetResetOffset();
}
break;
}
_parsedOffset++;
}
} while (ReadAvailableBytesToBuffer());
loopBreak:
if (_isGarbled && !message.IsMessageIncomplete)
{
message.IsMessageIncomplete = true;
}
OnMessageEnd();
GetMessage(buf);
}