public void ReadMessage()

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