Big changes
This commit is contained in:
@@ -0,0 +1,502 @@
|
||||
// **********************************************************************************************************
|
||||
// BytePackingXml.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.Xml;
|
||||
using System.Xml.XPath;
|
||||
|
||||
namespace Raytheon.Instruments.MessagingUtilities
|
||||
{
|
||||
// Takes an XML ICD and adds in nodes to represent the byte packing
|
||||
// The padding added will be displayed in the tool as arrays of characters
|
||||
internal class BytePackingXml : XmlDocument
|
||||
{
|
||||
private readonly int m_Packing = 8;
|
||||
private readonly Dictionary<string, double> m_ConstMap;
|
||||
private readonly Dictionary<string, int> m_SizeMap;
|
||||
private readonly Dictionary<string, int> m_PadMap;
|
||||
|
||||
public BytePackingXml(string icdStr) : base()
|
||||
{
|
||||
// Create the dictionaries
|
||||
m_ConstMap = new Dictionary<string, double>();
|
||||
m_PadMap = new Dictionary<string, int>();
|
||||
m_SizeMap = new Dictionary<string, int>();
|
||||
|
||||
// Create an XML document from the string
|
||||
LoadXml(icdStr);
|
||||
|
||||
XPathNavigator node = CreateNavigator();
|
||||
//Get the type of packing
|
||||
XPathNodeIterator nodeset = node.Select("/interface/packing");
|
||||
if (nodeset.MoveNext() == true)
|
||||
{
|
||||
if (!Parse.Try(nodeset.Current.Value.Trim(), out m_Packing))
|
||||
{
|
||||
switch (nodeset.Current.Value.Trim())
|
||||
{
|
||||
case "char":
|
||||
case "1":
|
||||
m_Packing = 1;
|
||||
break;
|
||||
case "short":
|
||||
case "2":
|
||||
m_Packing = 2;
|
||||
break;
|
||||
case "long":
|
||||
case "4":
|
||||
m_Packing = 4;
|
||||
break;
|
||||
case "double":
|
||||
case "8":
|
||||
default:
|
||||
m_Packing = 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle all of the constants
|
||||
nodeset = node.Select("/interface/constant");
|
||||
while (nodeset.MoveNext())
|
||||
{
|
||||
ProcessConstantNode(nodeset.Current);
|
||||
}
|
||||
|
||||
nodeset = node.Select("/interface/typedef");
|
||||
while (nodeset.MoveNext())
|
||||
{
|
||||
ProcessTypedefNode(nodeset.Current);
|
||||
}
|
||||
|
||||
nodeset = node.Select("/interface/enum");
|
||||
while (nodeset.MoveNext())
|
||||
{
|
||||
ProcessEnumerationNode(nodeset.Current);
|
||||
}
|
||||
|
||||
nodeset = node.Select("/interface/structure|/interface/message");
|
||||
while (nodeset.MoveNext())
|
||||
{
|
||||
ProcessStructureNode(nodeset.Current);
|
||||
}
|
||||
|
||||
NormalizeIcdLabels();
|
||||
}
|
||||
|
||||
// This function takes all of the messages in the ICD
|
||||
// and converts the labels into decimal, so when we do
|
||||
// a string lookup, they will all be in the same known format
|
||||
private void NormalizeIcdLabels()
|
||||
{
|
||||
XPathNavigator navigator = CreateNavigator();
|
||||
XPathNodeIterator nodeset;
|
||||
|
||||
nodeset = navigator.Select("/interface/message/label");
|
||||
while (nodeset.MoveNext())
|
||||
{
|
||||
try
|
||||
{
|
||||
double dLabel = GetConstFromString(nodeset.Current.Value);
|
||||
nodeset.Current.SetValue(((int)dLabel).ToString());
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new Exception("Message Label, " + nodeset.Current.Value + ", can not be converted to an integer");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessConstantNode(XPathNavigator node)
|
||||
{
|
||||
string name = "";
|
||||
string constStr = "";
|
||||
double constNum = 0;
|
||||
|
||||
if (node.MoveToChild("name", ""))
|
||||
{
|
||||
name = node.Value.Trim();
|
||||
node.MoveToParent();
|
||||
}
|
||||
if (node.MoveToChild("value", ""))
|
||||
{
|
||||
constStr = node.Value.Trim();
|
||||
if ((constStr.Length != 0) && (constStr[0] != '\"'))
|
||||
{
|
||||
constNum = GetConstFromString(constStr);
|
||||
}
|
||||
else
|
||||
{
|
||||
constNum = 0;
|
||||
}
|
||||
node.MoveToParent();
|
||||
}
|
||||
|
||||
// Verify the correctnes of the <constant> tag
|
||||
if ((name != "") && (constStr != ""))
|
||||
{
|
||||
AddItemToMap(m_ConstMap, name, constNum);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception(
|
||||
"ERROR: Constant Definition Incorrect - <name>:" + name +
|
||||
" <value>:" + constStr);
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessTypedefNode(XPathNavigator node)
|
||||
{
|
||||
string name = "";
|
||||
string type = "";
|
||||
int typeSize = 0; // Size of the item
|
||||
int typePad = 0; //Size of the largest item to pad to
|
||||
|
||||
if (node.MoveToChild("name", ""))
|
||||
{
|
||||
name = node.Value.Trim();
|
||||
node.MoveToParent();
|
||||
}
|
||||
if (node.MoveToChild("value", ""))
|
||||
{
|
||||
type = node.Value.Trim();
|
||||
GetSizeFromType(type, out typeSize, out typePad);
|
||||
node.MoveToParent();
|
||||
}
|
||||
|
||||
// Verify the correctnes of the <typedef> tag
|
||||
if ((name != "") && (type != ""))
|
||||
{
|
||||
AddItemToMap(m_PadMap, name, typePad);
|
||||
AddItemToMap(m_SizeMap, name, typeSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception(
|
||||
"ERROR: Typedef Definition Incorrect - <name>:" + name +
|
||||
" <value>:" + type);
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessEnumerationNode(XPathNavigator node)
|
||||
{
|
||||
string name;
|
||||
double constNum = 0;
|
||||
var constStr = string.Empty;
|
||||
|
||||
if (node.MoveToChild("name", ""))
|
||||
{
|
||||
name = node.Value.Trim();
|
||||
AddItemToMap(m_PadMap, name, 4);
|
||||
AddItemToMap(m_SizeMap, name, 4);
|
||||
node.MoveToParent();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("ERROR: Enumeration Definition Incorrect. No <name> tag present.");
|
||||
}
|
||||
|
||||
XPathNodeIterator nodeSet = node.Select("item|enum_item");
|
||||
while (nodeSet.MoveNext())
|
||||
{
|
||||
name = string.Empty;
|
||||
|
||||
if ((nodeSet.Current.MoveToChild("name", "")) ||
|
||||
(nodeSet.Current.MoveToChild("item_name", "")))
|
||||
{
|
||||
name = nodeSet.Current.Value.Trim();
|
||||
nodeSet.Current.MoveToParent();
|
||||
}
|
||||
if (nodeSet.Current.MoveToChild("value", ""))
|
||||
{
|
||||
constStr = nodeSet.Current.Value.Trim();
|
||||
constNum = GetConstFromString(constStr);
|
||||
nodeSet.Current.MoveToParent();
|
||||
}
|
||||
|
||||
// Verify the correctnes of the <enum><item> tag
|
||||
if ((name != "") && (constStr != ""))
|
||||
{
|
||||
AddItemToMap(m_ConstMap, name, constNum);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"ERROR: Enumeration Item Definition Incorrect - <name>: {name} <value>: {constStr}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessStructureNode(XPathNavigator node)
|
||||
{
|
||||
string name;
|
||||
|
||||
if (node.MoveToChild("name", ""))
|
||||
{
|
||||
name = node.Value.Trim();
|
||||
node.MoveToParent();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("ERROR: Stucture/Message Definition Incorrect. No <name> tag present.");
|
||||
}
|
||||
|
||||
int maxSize = 0;
|
||||
int padCount = 0;
|
||||
uint bitCount = 0; // Used to see how many bits have been processed.
|
||||
int lastItemSize = 0;
|
||||
|
||||
var nodeSet = node.Select("item|struct_item|msg_item");
|
||||
while (nodeSet.MoveNext())
|
||||
{
|
||||
GetItemSize(nodeSet.Current, out int padSize, out int itemSize, out int reps, out uint bits);
|
||||
if ((lastItemSize != itemSize) || ((bitCount + bits) > (uint)(itemSize * 8)))
|
||||
{
|
||||
bitCount = 0; // Size changed or bit rollover
|
||||
}
|
||||
|
||||
if (bitCount == 0)
|
||||
{
|
||||
padCount += AddPadding(node, nodeSet.Current, padSize, padCount);
|
||||
|
||||
// Set maxSize
|
||||
if (padSize > maxSize)
|
||||
{
|
||||
maxSize = padSize;
|
||||
}
|
||||
|
||||
// Keep up with the pad count
|
||||
padCount += (itemSize * reps);
|
||||
}
|
||||
|
||||
lastItemSize = itemSize;
|
||||
bitCount += bits;
|
||||
}
|
||||
|
||||
if (maxSize != 0)
|
||||
{
|
||||
// Add final padding
|
||||
padCount += AddPadding(node, null, maxSize, padCount);
|
||||
}
|
||||
|
||||
AddItemToMap(m_PadMap, name, maxSize);
|
||||
AddItemToMap(m_SizeMap, name, padCount);
|
||||
}
|
||||
|
||||
private void GetItemSize(XPathNavigator node, out int padSize, out int itemSize, out int reps, out uint bits)
|
||||
{
|
||||
string name = "";
|
||||
|
||||
if ((node.MoveToChild("name", "")) ||
|
||||
(node.MoveToChild("item_name", "")))
|
||||
{
|
||||
name = node.Value.Trim();
|
||||
node.MoveToParent();
|
||||
}
|
||||
|
||||
itemSize = -1;
|
||||
padSize = -1;
|
||||
reps = 1;
|
||||
bits = 0;
|
||||
|
||||
var nodeSet = node.Select("type");
|
||||
while (nodeSet.MoveNext())
|
||||
{
|
||||
GetSizeFromType(nodeSet.Current.Value.Trim(), out padSize, out itemSize);
|
||||
}
|
||||
|
||||
nodeSet = node.Select("bits");
|
||||
if (nodeSet.MoveNext())
|
||||
{
|
||||
bits = (uint)GetConstFromString(nodeSet.Current.Value.Trim());
|
||||
}
|
||||
|
||||
nodeSet = node.Select("arrayLength|imageWidth|imageHeight");
|
||||
while (nodeSet.MoveNext())
|
||||
{
|
||||
try
|
||||
{
|
||||
reps *= (int)GetConstFromString(nodeSet.Current.Value.Trim());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new Exception
|
||||
(e.Message + " item name = \"" + name + "\", tag = <" +
|
||||
nodeSet.Current.Name + ">.");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if ((itemSize == -1) || (padSize == -1))
|
||||
{
|
||||
throw new Exception
|
||||
("ERROR: Item named " + name + "does not contain a <type> tag.");
|
||||
}
|
||||
|
||||
if (bits == 0)
|
||||
bits = (uint)padSize * 8;
|
||||
}
|
||||
|
||||
private double GetConstFromString(string constStr)
|
||||
{
|
||||
if ((constStr.Length > 0) && (constStr[0] == '\''))
|
||||
{
|
||||
byte charData = (byte)constStr[1];
|
||||
constStr = charData.ToString();
|
||||
}
|
||||
|
||||
if (Parse.Try(constStr, out double data) == false)
|
||||
{
|
||||
if (Parse.Try(constStr, out int iData) == false)
|
||||
{
|
||||
try
|
||||
{
|
||||
data = m_ConstMap[constStr];
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new Exception("ERROR: ConstantValue - \"" + constStr + "\" does not resolve to a number.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
data = (double)iData;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
private void AddItemToMap(Dictionary<string, int> map, string name, int value)
|
||||
{
|
||||
if (map.ContainsKey(name))
|
||||
{
|
||||
throw new Exception("ERROR: Element " + name + " is defined multiple times.");
|
||||
}
|
||||
else
|
||||
{
|
||||
map.Add(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddItemToMap(Dictionary<string, double> map, string name, double value)
|
||||
{
|
||||
if (map.ContainsKey(name))
|
||||
{
|
||||
throw new Exception("ERROR: Element " + name + " is defined multiple times.");
|
||||
}
|
||||
else
|
||||
{
|
||||
map.Add(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
private void GetSizeFromType(string type, out int typePad, out int typeSize)
|
||||
{
|
||||
// Remove all whitespace
|
||||
type = type.Replace(" ", "");
|
||||
|
||||
if ((type == "char") || (type == "unsignedchar"))
|
||||
{
|
||||
typePad = 1;
|
||||
typeSize = 1;
|
||||
}
|
||||
else if ((type == "short") || (type == "unsignedshort"))
|
||||
{
|
||||
typePad = 2;
|
||||
typeSize = 2;
|
||||
}
|
||||
else if ((type == "unsigned") || (type == "unsignedint") ||
|
||||
(type == "int") || (type == "float") ||
|
||||
(type == "boolean") || (type == "address"))
|
||||
{
|
||||
typePad = 4;
|
||||
typeSize = 4;
|
||||
}
|
||||
else if ((type == "double") || (type == "longlong") ||
|
||||
(type == "unsignedlonglong"))
|
||||
{
|
||||
typePad = 8;
|
||||
typeSize = 8;
|
||||
}
|
||||
else // The type is complex and has already been defined
|
||||
{
|
||||
try
|
||||
{
|
||||
typePad = m_PadMap[type];
|
||||
typeSize = m_SizeMap[type];
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new Exception("ERROR: <type> - " + type + " used without being defined.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int AddPadding(XPathNavigator ParentElement, XPathNavigator CurrentElement, int padSize, int padCount)
|
||||
{
|
||||
int padAdd = 0;
|
||||
int padTo = padSize;
|
||||
|
||||
if (m_Packing < padSize)
|
||||
{
|
||||
padTo = m_Packing;
|
||||
}
|
||||
|
||||
if ((padTo != 0) && (padCount % padTo != 0))
|
||||
{
|
||||
padAdd = padTo - (padCount % padTo);
|
||||
InsertPaddingNode(ParentElement, CurrentElement, padAdd);
|
||||
}
|
||||
|
||||
return padAdd;
|
||||
}
|
||||
|
||||
private void InsertPaddingNode(XPathNavigator ParentElement, XPathNavigator CurrentElement, int padAdd)
|
||||
{
|
||||
string pad = "<item>" +
|
||||
"<name>" + Message.PADDING_ITEM_NAME + "</name>" +
|
||||
"<type>char</type>" +
|
||||
"<arrayLength>" + padAdd + "</arrayLength>" +
|
||||
"<instruType>S</instruType>" +
|
||||
"</item>";
|
||||
if (CurrentElement != null)
|
||||
{
|
||||
CurrentElement.InsertBefore(pad);
|
||||
}
|
||||
else // End padding
|
||||
{
|
||||
ParentElement.AppendChild(pad);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user