using System; using System.Collections.Generic; using System.Globalization; using System.Xml; using Decal.Adapter.NetParser; using Decal.Interop.Net; namespace Decal.Adapter; /// /// Protocol Message Data /// public class Message : MessageStruct { private static Dictionary mRecv; private static Dictionary mSend; private static Dictionary mTypes; private int mType; internal MessageStruct mStruct; /// /// Message Type /// public int Type => mType; /// /// Returns the number of fields (or vector length) /// public override int Count => mStruct.Count; /// /// Returns the specified field data /// /// Field index /// Field value public override object this[int index] => mStruct[index]; /// /// Returns the specified field data /// /// Field name /// Field value public override object this[string name] => mStruct[name]; /// /// Returns the raw bytes for this field /// public override byte[] RawData => mStruct.RawData; /// /// Returns the next object in the (parent) vector /// public override object Next => mStruct.Next; /// /// Returns the parent field /// public override MessageStruct Parent => mStruct.Parent; internal Message() { } internal Message(IMessage2 msg, MessageDirection dir) { mType = BitConverter.ToInt32(msg.RawData, 0); mStruct = new MessageStruct(msg.RawData, 4, GetParser(mType, dir)); } internal Message(byte[] Data, MemberParser Parser) { mType = BitConverter.ToInt32(Data, 0); mStruct = new MessageStruct(Data, 4, Parser); } internal Message(Message Source) { mType = Source.mType; mStruct = Source.mStruct; } internal static MemberParser GetParser(int type, MessageDirection dir) { MemberParser result = null; switch (dir) { case MessageDirection.Inbound: if (mRecv.ContainsKey(type)) { result = mRecv[type]; } break; case MessageDirection.Outbound: if (mSend.ContainsKey(type)) { result = mSend[type]; } break; } return result; } /// /// Return the field name for the specified index /// /// Field index /// Name of the field public override string Name(int index) { return mStruct.Name(index); } /// /// Returns the passed in value? /// /// /// public override string Name(string memberName) { return mStruct.Name(memberName); } /// /// Returns the specified child structure /// /// Field index /// MessageStruct for the specified field public override MessageStruct Struct(int index) { return mStruct.Struct(index); } /// /// Returns the specified child structure /// /// Field name /// MessageStruct for the specified field public override MessageStruct Struct(string name) { return mStruct.Struct(name); } /// /// Returns the specified field value /// /// Type of the field /// Field index /// Field value cast to the specified FieldType public override FieldType Value(int index) { return mStruct.Value(index); } /// /// Returns the specified field value /// /// Type of the field /// Field name /// Field value cast to the specified FieldType public override FieldType Value(string name) { return mStruct.Value(name); } /// /// Returns the raw bytes of the specified field /// /// Field index /// Raw field value public override byte[] RawValue(int index) { return mStruct.RawValue(index); } /// /// Returns the raw bytes of the specified field /// /// Field name /// Raw field value public override byte[] RawValue(string name) { return mStruct.RawValue(name); } internal static void Initialize(string xmlFile) { mRecv = new Dictionary(); mSend = new Dictionary(); mTypes = new Dictionary(); XmlDocument xmlDocument = new XmlDocument(); xmlDocument.Load(xmlFile); foreach (XmlNode item in xmlDocument.SelectNodes("/schema/datatypes/type")) { ParseType(item, xmlDocument); } foreach (XmlNode item2 in xmlDocument.SelectNodes("/schema/messages/message")) { ParseMessage(item2, xmlDocument); } } private static void ParseType(XmlNode node, XmlDocument doc) { XmlAttribute xmlAttribute = node.Attributes["name"]; if (xmlAttribute == null) { return; } string value = xmlAttribute.Value; if (mTypes.ContainsKey(value)) { return; } MemberParser memberParser = new MemberParser(); mTypes.Add(value, memberParser); xmlAttribute = node.Attributes["primitive"]; if (xmlAttribute != null && string.Compare(xmlAttribute.Value, "true", ignoreCase: true, CultureInfo.InvariantCulture) == 0) { if (string.Compare(value, "BYTE", ignoreCase: true, CultureInfo.InvariantCulture) == 0) { memberParser.MemberType = MemberParserType.BYTE; } else if (string.Compare(value, "WORD", ignoreCase: true, CultureInfo.InvariantCulture) == 0) { memberParser.MemberType = MemberParserType.WORD; } else if (string.Compare(value, "PackedWORD", ignoreCase: true, CultureInfo.InvariantCulture) == 0) { memberParser.MemberType = MemberParserType.PackedWORD; } else if (string.Compare(value, "DWORD", ignoreCase: true, CultureInfo.InvariantCulture) == 0) { memberParser.MemberType = MemberParserType.DWORD; } else if (string.Compare(value, "PackedDWORD", ignoreCase: true, CultureInfo.InvariantCulture) == 0) { memberParser.MemberType = MemberParserType.PackedDWORD; } else if (string.Compare(value, "QWORD", ignoreCase: true, CultureInfo.InvariantCulture) == 0) { memberParser.MemberType = MemberParserType.QWORD; } else if (string.Compare(value, "float", ignoreCase: true, CultureInfo.InvariantCulture) == 0) { memberParser.MemberType = MemberParserType.@float; } else if (string.Compare(value, "double", ignoreCase: true, CultureInfo.InvariantCulture) == 0) { memberParser.MemberType = MemberParserType.@double; } else if (string.Compare(value, "String", ignoreCase: true, CultureInfo.InvariantCulture) == 0) { memberParser.MemberType = MemberParserType.String; } else if (string.Compare(value, "WString", ignoreCase: true, CultureInfo.InvariantCulture) == 0) { memberParser.MemberType = MemberParserType.WString; } } else { memberParser.MemberType = MemberParserType.Struct; memberParser.Child = ParseStruct(node.ChildNodes, doc); } } private static void ParseMessage(XmlNode node, XmlDocument doc) { XmlAttribute xmlAttribute = node.Attributes["type"]; if (xmlAttribute == null) { return; } string text = xmlAttribute.Value; if (text[0] == '0' && (text[1] == 'x' || text[1] == 'X')) { text = text.Substring(2); } int key = int.Parse(text, NumberStyles.HexNumber); bool flag = true; bool flag2 = false; xmlAttribute = node.Attributes["direction"]; if (xmlAttribute != null) { if (string.Compare(xmlAttribute.Value, "outbound", ignoreCase: true, CultureInfo.InvariantCulture) == 0) { flag = false; flag2 = true; } else if (string.Compare(xmlAttribute.Value, "both", ignoreCase: true, CultureInfo.InvariantCulture) == 0) { flag2 = true; } } if ((flag && !mRecv.ContainsKey(key)) || (flag2 && !mSend.ContainsKey(key))) { MemberParser value = ParseStruct(node.ChildNodes, doc); if (flag && !mRecv.ContainsKey(key)) { mRecv.Add(key, value); } if (flag2 && !mSend.ContainsKey(key)) { mSend.Add(key, value); } } } private static MemberParser ParseStruct(XmlNodeList nodes, XmlDocument doc) { MemberParser memberParser = new MemberParser(); MemberParser memberParser2 = memberParser; int count = nodes.Count; for (int i = 0; i < count; i++) { XmlNode xmlNode = nodes[i]; if (xmlNode.NodeType != XmlNodeType.Element) { continue; } string name = xmlNode.Name; if (string.Compare(name, "field", ignoreCase: true, CultureInfo.InvariantCulture) == 0) { XmlAttribute xmlAttribute = xmlNode.Attributes["type"]; if (xmlAttribute != null) { string value = xmlAttribute.Value; if (!mTypes.ContainsKey(value)) { ParseType(doc.SelectSingleNode("/schema/datatypes/type[@name='" + value + "']"), doc); } memberParser2.Next = new MemberParser(mTypes[value]); memberParser2 = memberParser2.Next; memberParser2.MemberName = xmlNode.Attributes["name"].Value; } } else if (string.Compare(name, "maskmap", ignoreCase: true, CultureInfo.InvariantCulture) == 0) { XmlAttribute xmlAttribute = xmlNode.Attributes["xor"]; long conditionXor = 0L; string value; if (xmlAttribute != null) { value = xmlAttribute.Value; if (value[0] == '0' && (value[1] == 'x' || value[1] == 'X')) { value = value.Substring(2); } conditionXor = long.Parse(value, NumberStyles.HexNumber); } value = xmlNode.Attributes["name"].Value; memberParser2.Next = ParseMaskMap(xmlNode.ChildNodes, doc); while (memberParser2.Next != null) { memberParser2 = memberParser2.Next; memberParser2.Condition = MemberParserCondition.NE; memberParser2.ConditionResult = 0L; memberParser2.ConditionField = value; memberParser2.ConditionXor = conditionXor; } } else if (string.Compare(name, "switch", ignoreCase: true, CultureInfo.InvariantCulture) == 0) { string value = xmlNode.Attributes["name"].Value; XmlAttribute xmlAttribute = xmlNode.Attributes["mask"]; long conditionXor = -1L; if (xmlAttribute != null) { value = xmlAttribute.Value; if (value[0] == '0' && (value[1] == 'x' || value[1] == 'X')) { value = value.Substring(2); } conditionXor = long.Parse(value, NumberStyles.HexNumber); } memberParser2.Next = ParseSwitch(xmlNode.ChildNodes, doc); while (memberParser2.Next != null) { memberParser2 = memberParser2.Next; memberParser2.Condition = MemberParserCondition.EQ; memberParser2.ConditionField = value; memberParser2.ConditionAnd = conditionXor; } } else if (string.Compare(name, "vector", ignoreCase: true, CultureInfo.InvariantCulture) == 0) { memberParser2.Next = new MemberParser(); memberParser2 = memberParser2.Next; memberParser2.MemberType = MemberParserType.Vector; memberParser2.MemberName = xmlNode.Attributes["name"].Value; memberParser2.LengthField = xmlNode.Attributes["length"].Value; XmlAttribute xmlAttribute = xmlNode.Attributes["mask"]; long conditionXor = -1L; if (xmlAttribute != null) { string value = xmlAttribute.Value; if (value[0] == '0' && (value[1] == 'x' || value[1] == 'X')) { value = value.Substring(2); } conditionXor = long.Parse(value, NumberStyles.HexNumber); } memberParser2.LengthMask = conditionXor; xmlAttribute = xmlNode.Attributes["skip"]; int num = 0; if (xmlAttribute != null) { string value = xmlAttribute.Value; if (value[0] == '0' && (value[1] == 'x' || value[1] == 'X')) { value = value.Substring(2); } num = int.Parse(value, NumberStyles.HexNumber); } memberParser2.LengthDelta = -num; memberParser2.Child = ParseStruct(xmlNode.ChildNodes, doc); } else if (string.Compare(name, "align", ignoreCase: true, CultureInfo.InvariantCulture) == 0) { string value = xmlNode.Attributes["type"].Value; if (string.Compare(value, "WORD", ignoreCase: true, CultureInfo.InvariantCulture) == 0) { memberParser2.PostAlignment = 2; } else if (string.Compare(value, "DWORD", ignoreCase: true, CultureInfo.InvariantCulture) == 0) { memberParser2.PostAlignment = 4; } else if (string.Compare(value, "QWORD", ignoreCase: true, CultureInfo.InvariantCulture) == 0) { memberParser2.PostAlignment = 8; } } } if (memberParser.PostAlignment != 0 && memberParser.Next != null) { memberParser.Next.PreAlignment = memberParser.PostAlignment; } return memberParser.Next; } private static MemberParser ParseMaskMap(XmlNodeList nodes, XmlDocument doc) { MemberParser memberParser = new MemberParser(); MemberParser memberParser2 = memberParser; int count = nodes.Count; for (int i = 0; i < count; i++) { XmlNode xmlNode = nodes[i]; if (xmlNode.NodeType != XmlNodeType.Element || string.Compare(xmlNode.Name, "mask", ignoreCase: true, CultureInfo.InvariantCulture) != 0) { continue; } long conditionAnd = 0L; XmlAttribute xmlAttribute = xmlNode.Attributes["value"]; if (xmlAttribute != null) { string text = xmlAttribute.Value; if (text[0] == '0' && (text[1] == 'x' || text[1] == 'X')) { text = text.Substring(2); } conditionAnd = long.Parse(text, NumberStyles.HexNumber); } memberParser2.Next = new MemberParser(); memberParser2 = memberParser2.Next; memberParser2.MemberType = MemberParserType.Case; memberParser2.ConditionAnd = conditionAnd; memberParser2.Child = ParseStruct(xmlNode.ChildNodes, doc); } return memberParser.Next; } private static MemberParser ParseSwitch(XmlNodeList nodes, XmlDocument doc) { MemberParser memberParser = new MemberParser(); MemberParser memberParser2 = memberParser; int count = nodes.Count; for (int i = 0; i < count; i++) { XmlNode xmlNode = nodes[i]; if (xmlNode.NodeType != XmlNodeType.Element || string.Compare(xmlNode.Name, "case", ignoreCase: true, CultureInfo.InvariantCulture) != 0) { continue; } long conditionResult = 0L; XmlAttribute xmlAttribute = xmlNode.Attributes["value"]; if (xmlAttribute != null) { string text = xmlAttribute.Value; if (text[0] == '0' && (text[1] == 'x' || text[1] == 'X')) { text = text.Substring(2); } conditionResult = long.Parse(text, NumberStyles.HexNumber); } memberParser2.Next = new MemberParser(); memberParser2 = memberParser2.Next; memberParser2.MemberType = MemberParserType.Case; memberParser2.ConditionResult = conditionResult; memberParser2.Child = ParseStruct(xmlNode.ChildNodes, doc); } return memberParser.Next; } }