// ********************************************************************************************************** // MessageXmlDocument.cs // 5/18/2022 // NGI - Next Generation Interceptor // // Contract No. HQ0856-21-C-0003/1022000209 // // THIS DOCUMENT DOES NOT CONTAIN TECHNOLOGY OR TECHNICAL DATA CONTROLLED UNDER EITHER THE U.S. // INTERNATIONAL TRAFFIC IN ARMS REGULATIONS OR THE U.S. EXPORT ADMINISTRATION REGULATIONS. // // RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION PROPRIETARY TO RAYTHEON // COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. // DISCLOSURE TO UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO RAYTHEON // COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS CONTENTS SHALL BE FURNISHED OR DISCLOSED // TO OR COPIED OR USED BY PERSONS OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF // RAYTHEON COMPANY. // // UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. // // DESTRUCTION NOTICE: FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN DOD 5220.22-M, // NATIONAL INDUSTRIAL SECURITY PROGRAM OPERATING MANUAL, FEBRUARY 2006, // INCORPORATING CHANGE 1, MARCH 28, 2013, CHAPTER 5, SECTION 7, OR DODM 5200.01-VOLUME 3, // DOD INFORMATION SECURITY PROGRAM: PROTECTION OF CLASSIFIED INFORMATION, ENCLOSURE 3, // SECTION 17. FOR CONTROLLED UNCLASSIFIED INFORMATION FOLLOW THE PROCEDURES IN DODM 5200.01-VOLUME 4, // INFORMATION SECURITY PROGRAM: CONTROLLED UNCLASSIFIED INFORMATION. // // CONTROLLED BY: MISSILE DEFENSE AGENCY // CONTROLLED BY: GROUND-BASED MIDCOURSE DEFENSE PROGRAM OFFICE // CUI CATEGORY: CTI // DISTRIBUTION/DISSEMINATION CONTROL: F // POC: Alex Kravchenko (1118268) // ********************************************************************************************************** using System; using System.Collections.Generic; using System.Text; using System.Xml; using System.Xml.XPath; using System.Diagnostics; using System.Threading; using NLog; namespace Raytheon.Instruments.MessagingUtilities { public class MessageXmlDocument : XmlDocument { private readonly ILogger _logger; private readonly string _XmlFileName; private string BuiltXML = ""; private uint m_MaxMsgSize = 0; private readonly List m_IncludeList; private MessageXmlDocument() : base() { } public MessageXmlDocument(string Pathname, ILogger logger) : base() { _logger = logger; _XmlFileName = Pathname; m_IncludeList = new List(); RecurseProcessing(Pathname); BuiltXML = string.Concat(BuiltXML, ""); BytePackingXml addPacking = new BytePackingXml(BuiltXML); LoadXml(addPacking.OuterXml); } public Dictionary GetEnumerations(string Type) { Dictionary enumList = new Dictionary(); // Get XML nodes to parse the XML ICD document XPathNavigator Node = CreateNavigator(); XPathNodeIterator Nodeset = Node.Select("interface/enum/name"); while (Nodeset.MoveNext()) { // Find the enumeration with the name of the type if (Nodeset.Current.Value.Trim().Equals(Type.Trim())) { // Find all the enumeration items XPathNavigator enumNode = Nodeset.Current.Clone(); while (enumNode.MoveToNext()) { if (enumNode.Name.Trim().Equals("item") || enumNode.Name.Trim().Equals("enum_item")) { string name = null; string value = null; // Find all name nodes XPathNavigator childNode = enumNode.Clone(); childNode.MoveToFirstChild(); do { if (childNode.Name.Trim().Equals("name")) { name = childNode.Value.Trim(); } else if (childNode.Name.Trim().Equals("item_name")) { name = childNode.Value.Trim(); } if (childNode.Name.Trim().Equals("value")) { value = childNode.Value.Trim(); } // Once we find the name & value, add it to the list if ((name != null) && (value != null)) { enumList.Add(name, value); break; } } while (childNode.MoveToNext()); } } break; // We found the enumeration we wanted } } return enumList; } private void RecurseProcessing(string pathName) { string directory; string IncludePathname; XPathNodeIterator nodeset; // Only process each file once pathName = pathName.Replace('/', '\\'); if (m_IncludeList.Contains(pathName)) { return; // This file has already been processed } else { m_IncludeList.Add(pathName); } _logger.Log(LogLevel.Info, $"Loading File: {pathName}"); XPathDocument document = new XPathDocument(pathName); XPathNavigator navigator = document.CreateNavigator(); // Verify this is a COE XML ICD nodeset = navigator.Select("/interface"); if (nodeset.Count == 0) { // This is not an XML ICD throw new Exception($"Invalid COE XML Format. Unable to process {pathName}" + "\nEnsure this is a properly formatted ICD."); } nodeset = navigator.Select("/interface/include/file"); while (nodeset.MoveNext()) { try { directory = DirectoryOf(pathName); } catch { directory = ".\\"; } IncludePathname = nodeset.Current.Value.Trim(); if ((!IncludePathname.StartsWith("\\")) && (!IncludePathname.Contains(":"))) { while (IncludePathname.StartsWith(".")) { if ((IncludePathname.StartsWith("..\\")) || (IncludePathname.StartsWith("../"))) { directory = DirectoryOf(directory); IncludePathname = IncludePathname.Remove(0, 3); } else if ((IncludePathname.StartsWith(".\\")) || (IncludePathname.StartsWith("./"))) { IncludePathname = IncludePathname.Remove(0, 2); } } IncludePathname = string.Concat(directory, "\\", IncludePathname); } RecurseProcessing(IncludePathname); } nodeset = navigator.Select("/interface/packing|/interface/typedef|/interface/constant|interface/enum|/interface/structure|/interface/message"); while (nodeset.MoveNext()) { string item = nodeset.Current.OuterXml; int index; while ((index = item.IndexOf("")) != -1) { item = item.Remove(index, item.IndexOf("") + 14 - index); } while ((index = item.IndexOf("") + 3 - index); } while (item.IndexOf("> ") != -1) { item = item.Replace("> ", ">"); } while (item.IndexOf(" <") != -1) { item = item.Replace(" <", "<"); } //_logger.Log(LogLevel.Trace, $"Loading Node :\n{item}"); Thread.Sleep(1); BuiltXML = string.Concat(BuiltXML, item); } } private string DirectoryOf(string Pathname) { return Pathname.Remove(Pathname.LastIndexOf("\\")); } // // From the XML document, the definition of a single message can be identified // from the Message Name and returned as an XML string. // public string XmlFileName { get { return _XmlFileName; } } public string GetMessage(string messageName) { string message; messageName = messageName.Trim(); _logger.Log(LogLevel.Info, $"Searching for message : {messageName}"); try { message = SelectSingleNode($"/interface/message[name='{messageName}']").OuterXml; message = TranslateValue(message); _logger.Log(LogLevel.Trace, $"Found by name: {message}"); } catch { message = null; _logger.Log(LogLevel.Error, "Message not found"); } return message; } // // From the XML document, the definition of a single message can be identified // from the Message Label and returned as an XML string. // public string GetMessageFromLabel(string messageLabel) { string message; string msgLabel = ""; if (Parse.Try(messageLabel, out int label) == true) { msgLabel = label.ToString(); } _logger.Log(LogLevel.Info, $"Searching for message: {msgLabel}"); try { // Search by message label message = SelectSingleNode($"/interface/message[label='{msgLabel}']").OuterXml; message = TranslateValue(message); _logger.Log(LogLevel.Trace, $"Found by label: {message}"); } catch { try { // Search by instruLabel message = SelectSingleNode($"/interface/message[instruLabel='{messageLabel}']").OuterXml; message = TranslateValue(message); _logger.Log(LogLevel.Trace, $"Found by instrument Label: {message}"); } catch { message = null; _logger.Log(LogLevel.Error, "Message not found"); } } return message; } // // From the XML document, the definition of a single message can be identified // from the Message InstruLabel and returned as an XML string. // public string GetMessageFromInstruLabel(string messageInstruLabel) { string message; messageInstruLabel = messageInstruLabel.Trim(); _logger.Log(LogLevel.Info, $"Searching for message: {messageInstruLabel}"); try { message = SelectSingleNode($"/interface/message[instruLabel='{messageInstruLabel}']").OuterXml; message = TranslateValue(message); _logger.Log(LogLevel.Trace, $"Found by instrument label: {message}"); } catch { message = null; _logger.Log(LogLevel.Error, "Message not found"); } return message; } public uint GetLargestMessageSize() { lock (this) { // return the max message size if we have already calculated it if (m_MaxMsgSize != 0) { return m_MaxMsgSize; } else { DateTime t1 = DateTime.Now; XPathNavigator navigator = CreateNavigator(); XPathNodeIterator nodeset = navigator.Select("/interface/message/name"); while (nodeset.MoveNext()) { Message msg = new Message(nodeset.Current.Value.Trim(), this); uint msgSize = msg.GetMessageSize(); if (msgSize > m_MaxMsgSize) { m_MaxMsgSize = msgSize; } } DateTime t2 = DateTime.Now; TimeSpan duration = t2 - t1; Debug.WriteLine("Max Msg Size Algorithm Time = " + duration); } } return m_MaxMsgSize; } public uint GetMessageSize(string MsgName) { uint msg_size = 0; lock (this) { XPathNavigator navigator = CreateNavigator(); XPathNodeIterator nodeset = navigator.Select("/interface/message/name"); while (nodeset.MoveNext()) { if (MsgName == nodeset.Current.Value.Trim()) { Message msg = new Message(nodeset.Current.Value.Trim(), this); msg_size = msg.GetMessageSize(); } } } return msg_size; } // // Since the XML message definitions contain the definitions of all the enumerations and constants, // this object is the only one containing the knowledge to interpret strings using enumerations and/or // constants. This method will substitute enumerations and constants with their respective base values // in a specified string. // public string TranslateValue(string Value) { XPathNavigator navigator = CreateNavigator(); XPathNavigator position; string NewValue = Value; // // Substitute enumeration // try { position = navigator.SelectSingleNode("/interface/enum/item[name='" + NewValue + "']"); if (position == null) { position = navigator.SelectSingleNode("/interface/enum/item[item_name='" + NewValue + "']"); } if (position != null) { position.MoveToChild("value", ""); NewValue = position.Value; } // // Substitute constants // position = navigator.SelectSingleNode("/interface/constant[name='" + NewValue + "']"); if (position != null) { NewValue = position.Value; _logger.Log(LogLevel.Info, "Translating field value : " + Value + " -> " + NewValue); } } catch (Exception e) { _logger.Error(e.Message); } return NewValue; } } }