diff --git a/QuickFIXn/Message/Message.cs b/QuickFIXn/Message/Message.cs
index 5bfc60360..333f286b4 100644
--- a/QuickFIXn/Message/Message.cs
+++ b/QuickFIXn/Message/Message.cs
@@ -83,6 +83,39 @@ public static MsgType IdentifyType(string fixstring)
return new MsgType(GetMsgType(fixstring));
}
+ public static int ExtractFieldTag(string msgstr, int pos)
+ {
+ int tagend = msgstr.IndexOf('=', pos);
+ int tag = Convert.ToInt32(msgstr.Substring(pos, tagend - pos));
+ return tag;
+ }
+
+ public static StringField ExtractDataField(string msgstr, int dataLength, ref int pos)
+ {
+ try
+ {
+ int tagend = msgstr.IndexOf('=', pos);
+ int tag = Convert.ToInt32(msgstr.Substring(pos, tagend - pos));
+ pos = tagend + 1;
+ StringField field = new StringField(tag, msgstr.Substring(pos, dataLength));
+
+ pos += dataLength + 1;
+ return field;
+ }
+ catch (ArgumentOutOfRangeException e)
+ {
+ throw new MessageParseError($"Error at position ({pos}) while parsing msg ({msgstr})", e);
+ }
+ catch (OverflowException e)
+ {
+ throw new MessageParseError($"Error at position ({pos}) while parsing msg ({msgstr})", e);
+ }
+ catch (FormatException e)
+ {
+ throw new MessageParseError($"Error at position ({pos}) while parsing msg ({msgstr})", e);
+ }
+ }
+
public static StringField ExtractField(string msgstr, ref int pos)
{
try
@@ -314,9 +347,20 @@ public void FromString(
while (pos < msgstr.Length)
{
- StringField f = ExtractField(msgstr, ref pos);
-
- if (validate && count < 3 && Header.HEADER_FIELD_ORDER[count++] != f.Tag)
+ StringField? f = null;
+
+ int fieldTag = ExtractFieldTag(msgstr, pos);
+ if (fieldTag == Tags.XmlData)
+ {
+ if (IsHeaderField(Tags.XmlDataLen))
+ f = ExtractDataField(msgstr, Header.GetInt(Tags.XmlDataLen), ref pos);
+ else if (IsSetField(Tags.XmlDataLen))
+ f = ExtractDataField(msgstr, GetInt(Tags.XmlDataLen), ref pos);
+ }
+
+ f ??= ExtractField(msgstr, ref pos);
+
+ if (validate && (count < 3) && (Header.HEADER_FIELD_ORDER[count++] != f.Tag))
throw new InvalidMessage("Header fields out of order");
if (IsHeaderField(f.Tag, transportDict))
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index dd5097afa..c767ab24c 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -66,6 +66,7 @@ What's New
* #697 - new SocketIgnoreProxy setting (ABSJ415)
* #740 - Capture inner exception messages when handling authentication exceptions (rars)
* #833 - Add Try/Catch logic to SocketInitiator.OnStart() (Falcz)
+* #782 - proper handling of XmlData field (larsope)
### v1.11.2:
* same as v1.11.1, but I fixed the readme in the pushed nuget packages
diff --git a/UnitTests/MessageTests.cs b/UnitTests/MessageTests.cs
index a8b5dcfda..315f75ae8 100644
--- a/UnitTests/MessageTests.cs
+++ b/UnitTests/MessageTests.cs
@@ -13,6 +13,8 @@ public class MessageTests
{
private IMessageFactory _defaultMsgFactory = new DefaultMessageFactory();
+ private const char Nul = Message.SOH;
+
[Test]
public void IdentifyTypeTest()
{
@@ -372,6 +374,52 @@ public void NestedRepeatingGroupParseGroupTest()
Assert.That(subGrp.GetString(Tags.PartySubID), Is.EqualTo("OHAI123"));
}
+ [Test]
+ public void ReadXmlDataTest() {
+ // Use tag 212/XmlDataLen to properly read 213/XmlData
+
+ QuickFix.DataDictionary.DataDictionary dd = new QuickFix.DataDictionary.DataDictionary();
+ dd.LoadFIXSpec("FIX42");
+
+ QuickFix.FIX42.NewOrderSingle n = new QuickFix.FIX42.NewOrderSingle();
+
+ string s = "8=FIX.4.2" + Nul + "9=495" + Nul + "35=n" + Nul + "34=31420" + Nul + "369=1003" + Nul +
+ "52=20200701-20:34:33.978" + Nul + "49=CME" + Nul + "50=84" +
+ Nul + "56=DUMMY11" + Nul + "57=SID1" + Nul + "143=US,IL" + Nul + "212=392" + Nul +
+ "213=8=FIX.4.2" + Nul + "9=356" + Nul + "35=8" + Nul + "34=36027" + Nul +
+ "369=18623" + Nul + "52=20200701-20:34:33.977" + Nul + "49=CME" + Nul + "50=84" + Nul +
+ "56=M2L000N" + Nul + "57=DUMMY" + Nul + "143=US,IL" + Nul + "1=00331" + Nul +
+ "6=0" + Nul + "11=ACP1593635673935" + Nul + "14=0" + Nul + "17=84618:1342652" + Nul + "20=0" +
+ Nul + "37=84778833500" + Nul + "38=10" + Nul + "39=0" + Nul + "40=2" + Nul +
+ "41=0" + Nul + "44=139.203125" + Nul + "48=204527" + Nul + "54=1" + Nul + "55=ZN" + Nul +
+ "59=0" + Nul + "60=20200701-20:34:33.976" + Nul + "107=ZNH1" + Nul + "150=0" + Nul +
+ "151=10" + Nul + "167=FUT" + Nul + "432=20200701" + Nul + "1028=Y" + Nul + "1031=Y" + Nul +
+ "5979=1593635673976364291" + Nul + "9717=ACP1593635673935" + Nul + "10=124" + Nul + "" +
+ Nul + "10=028" + Nul;
+
+ n.FromString(s, true, dd, dd, _defaultMsgFactory);
+
+ //verify that the data field was read correctly
+ Assert.AreEqual(n.Header.GetInt(212), n.Header.GetString(213).Length);
+ }
+
+ [Test]
+ public void XmlDataWithoutLengthTest() {
+ QuickFix.DataDictionary.DataDictionary dd = new QuickFix.DataDictionary.DataDictionary();
+ dd.LoadFIXSpec("FIX42");
+
+ QuickFix.FIX42.NewOrderSingle n = new QuickFix.FIX42.NewOrderSingle();
+
+ string s = "8=FIX.4.2" + Nul + "9=495" + Nul + "35=n" + Nul + "34=31420" + Nul + "369=1003" + Nul +
+ "52=20200701-20:34:33.978" + Nul + "49=CME" + Nul + "50=84" +
+ Nul + "56=DUMMY11" + Nul + "57=SID1" + Nul + "143=US,IL" + Nul +
+ "213=oops my length field 212 is missing" +
+ Nul + "10=028" + Nul;
+
+ FieldNotFoundException ex =
+ Assert.Throws(delegate { n.FromString(s, true, dd, dd, _defaultMsgFactory); });
+ Assert.AreEqual("field not found for tag: 212", ex!.Message);
+ }
[Test]