330 lines
15 KiB
C#
330 lines
15 KiB
C#
// **********************************************************************************************************
|
|
// XmlMbitParser.cs
|
|
// 6/6/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.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Xml;
|
|
using System.Xml.XPath;
|
|
|
|
namespace Raytheon.Instruments.XmlUtilities
|
|
{
|
|
public class XmlMbitParser
|
|
{
|
|
private readonly NLog.Logger _logger = NLog.LogManager.GetCurrentClassLogger();
|
|
|
|
private readonly Dictionary<string, XmlParser.CommonXmlElements> _commonElements = new Dictionary<string, XmlParser.CommonXmlElements>(StringComparer.InvariantCultureIgnoreCase);
|
|
|
|
// store messages defined in xml files
|
|
private readonly List<XmlParser.XmlMbitMessage> _mbitMessages = new List<XmlParser.XmlMbitMessage>();
|
|
|
|
// store duplicate messages for diagnostic purposes
|
|
private readonly Dictionary<string, List<string>> _duplicateMbitMessages = new Dictionary<string, List<string>>();
|
|
|
|
// store each enumeration type and its associate key/value pairs
|
|
private readonly Dictionary<string, XmlParser.XmlEnumeration> _xmlEnums = new Dictionary<string, XmlParser.XmlEnumeration>(StringComparer.InvariantCultureIgnoreCase);
|
|
|
|
// store duplicate enumerations for diagnostic purposes
|
|
private readonly Dictionary<string, List<string>> _duplicateEnums = new Dictionary<string, List<string>>();
|
|
|
|
// store each structure type and its associated data members
|
|
private readonly Dictionary<string, XmlParser.XmlStructure> _xmlStructures = new Dictionary<string, XmlParser.XmlStructure>(StringComparer.InvariantCultureIgnoreCase);
|
|
|
|
// store duplicate structures for diagnostic purposes
|
|
private readonly Dictionary<string, List<string>> _duplicateStructures = new Dictionary<string, List<string>>();
|
|
|
|
// look up table for constants, the key is the constant name. A constant name can be defined in more than one namespace and have different values
|
|
private ILookup<string, XmlParser.XmlConstant> _xmlConstantsLookUpByConstantName = null;
|
|
|
|
// look up table for constants, the key is the namespace in which the constant is defined. A constant name can be defined in more than one namespace and have different values
|
|
private ILookup<string, XmlParser.XmlConstant> _xmlConstantsLookUpByNameSpace = null;
|
|
|
|
// store duplicate constants for diagnostic purposes
|
|
private readonly Dictionary<string, List<string>> _duplicateConstants = new Dictionary<string, List<string>>();
|
|
|
|
// store names of files that contain data types that we need to generate
|
|
public List<string> m_dataTypeFilesToBeGenerated = new List<string>();
|
|
|
|
/// <summary>
|
|
/// Parse XML files from the path folder
|
|
/// </summary>
|
|
/// <param name="path"></param>
|
|
/// <returns></returns>
|
|
public bool ParseXmlFiles(string path)
|
|
{
|
|
bool isSuccessful = true;
|
|
string xmlNamespace = string.Empty;
|
|
List<XmlParser.XmlConstant> constantList = new List<XmlParser.XmlConstant>();
|
|
|
|
if (!Directory.Exists(path))
|
|
{
|
|
_logger.Error($"Path {path} not found");
|
|
|
|
isSuccessful = false;
|
|
return isSuccessful;
|
|
}
|
|
|
|
string[] files = Directory.GetFiles(path, "*.xml", SearchOption.AllDirectories);
|
|
|
|
List<string> dataTypeFiles = new List<string>(files.ToList());
|
|
|
|
foreach (string xmlFile in dataTypeFiles)
|
|
{
|
|
XPathDocument doc = null;
|
|
|
|
int prevEnumCount = _xmlEnums.Count;
|
|
int prevStructureCount = _xmlStructures.Count;
|
|
int prevMessageCount = _mbitMessages.Count;
|
|
int prevConstantCount = constantList.Count;
|
|
|
|
List<string> comments = new List<string>();
|
|
|
|
try
|
|
{
|
|
XmlReaderSettings readerSettings = new XmlReaderSettings()
|
|
{
|
|
// tells the xmlreader to ignore comment in XML file
|
|
IgnoreComments = true
|
|
};
|
|
|
|
using (XmlReader reader = XmlReader.Create(xmlFile, readerSettings))
|
|
{
|
|
// load the XML file
|
|
doc = new XPathDocument(reader);
|
|
}
|
|
|
|
XPathNavigator nav = doc.CreateNavigator();
|
|
|
|
xmlNamespace = Path.GetFileNameWithoutExtension(xmlFile);
|
|
|
|
_commonElements[xmlNamespace] = new XmlParser.CommonXmlElements();
|
|
|
|
nav.MoveToRoot();
|
|
|
|
try
|
|
{
|
|
_logger.Info($"Parsing {Path.GetFileName(xmlFile)}");
|
|
|
|
if (nav.MoveToFirstChild())
|
|
{
|
|
do
|
|
{
|
|
if (string.Equals(nav.Name, "interface", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
if (nav.MoveToFirstChild())
|
|
{
|
|
do
|
|
{
|
|
if (!XmlParser.GetCommonElementsFromXml(nav, _commonElements[xmlNamespace]))
|
|
{
|
|
if (string.Equals(nav.Name, "enum", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
XmlParser.GetEnumeration(nav, xmlNamespace, _xmlEnums, _duplicateEnums);
|
|
}
|
|
else if (string.Equals(nav.Name, "structure", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
XmlParser.GetStructure(nav, xmlNamespace, _xmlStructures, comments, _duplicateStructures);
|
|
comments.Clear();
|
|
}
|
|
else if (string.Equals(nav.Name, "constant", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
XmlParser.GetConstant(nav, xmlNamespace, constantList, _duplicateConstants);
|
|
}
|
|
else if (string.Equals(nav.Name, "message", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
XmlParser.GetMbitMessage(nav, xmlNamespace, _mbitMessages, _duplicateMbitMessages);
|
|
}
|
|
else if (string.Equals(nav.Name, "comment", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
comments.Add(nav.Value.Trim());
|
|
}
|
|
else if (nav.Name.Length > 0)
|
|
{
|
|
throw new XmlParsingException("Unknown element \"" + nav.OuterXml.Substring(0, nav.OuterXml.IndexOf(">") + 1) + "\" on line " + ((IXmlLineInfo)nav).LineNumber.ToString());
|
|
}
|
|
}
|
|
} while (nav.MoveToNext());
|
|
}
|
|
}
|
|
} while (nav.MoveToNext());
|
|
}
|
|
}
|
|
catch (XmlParsingException ex)
|
|
{
|
|
string message = "File : " + xmlFile + "\n" + ex.Message;
|
|
throw new Exception(message);
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_logger.Error(e);
|
|
isSuccessful = false;
|
|
}
|
|
|
|
if (isSuccessful)
|
|
{
|
|
_logger.Info(" - SUCCESS");
|
|
|
|
_logger.Info("Results:");
|
|
_logger.Info($"Constants: {constantList.Count - prevConstantCount}");
|
|
_logger.Info($"Enumerations: {_xmlEnums.Count - prevEnumCount}");
|
|
_logger.Info($"Structures: {_xmlStructures.Count - prevStructureCount}");
|
|
_logger.Info($"Messages: {_mbitMessages.Count - prevMessageCount}");
|
|
}
|
|
else
|
|
{
|
|
_logger.Warn(" - FAIL");
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (constantList.Count > 0)
|
|
{
|
|
// we want to create a look up table from a list of constants
|
|
// the key for this table will be the constant name
|
|
_xmlConstantsLookUpByConstantName = constantList.ToLookup(item => item.name);
|
|
|
|
// we want to create a look up table from a list of constants
|
|
// the key for this table will be the namespace
|
|
_xmlConstantsLookUpByNameSpace = constantList.ToLookup(item => item.nameSpace);
|
|
}
|
|
|
|
if (_duplicateMbitMessages.Count > 0 || _duplicateConstants.Count > 0 || _duplicateEnums.Count > 0 || _duplicateStructures.Count > 0)
|
|
{
|
|
StreamWriter writer = null;
|
|
FileStream fs = null;
|
|
bool firstLineInFileAllocated = false;
|
|
string textToBeWrittenToFile = string.Empty;
|
|
string diagnosticFile = Path.Combine(path, "diagnostics.txt");
|
|
|
|
_logger.Info("Generating diagnostic information...");
|
|
|
|
foreach (KeyValuePair<string, List<string>> dictItem in _duplicateMbitMessages)
|
|
{
|
|
if (!firstLineInFileAllocated)
|
|
firstLineInFileAllocated = true;
|
|
else
|
|
textToBeWrittenToFile += "\r\n\r\n";
|
|
|
|
textToBeWrittenToFile += "Duplicate definition for message \"" + dictItem.Key + "\" found in the following files: ";
|
|
foreach (string listItem in dictItem.Value)
|
|
{
|
|
textToBeWrittenToFile += "\r\n" + GetCodeIndentation(1) + listItem;
|
|
}
|
|
}
|
|
|
|
foreach (KeyValuePair<string, List<string>> dictItem in _duplicateStructures)
|
|
{
|
|
if (!firstLineInFileAllocated)
|
|
firstLineInFileAllocated = true;
|
|
else
|
|
textToBeWrittenToFile += "\r\n\r\n";
|
|
|
|
textToBeWrittenToFile += "Duplicate definition for structure \"" + dictItem.Key + "\" found in the following files: ";
|
|
foreach (string listItem in dictItem.Value)
|
|
{
|
|
textToBeWrittenToFile += "\r\n" + GetCodeIndentation(1) + listItem;
|
|
}
|
|
}
|
|
|
|
foreach (KeyValuePair<string, List<string>> dictItem in _duplicateEnums)
|
|
{
|
|
if (!firstLineInFileAllocated)
|
|
firstLineInFileAllocated = true;
|
|
else
|
|
textToBeWrittenToFile += "\r\n\r\n";
|
|
|
|
textToBeWrittenToFile += "Duplicate definition for enum \"" + dictItem.Key + "\" found in the following files: ";
|
|
foreach (string listItem in dictItem.Value)
|
|
{
|
|
textToBeWrittenToFile += "\r\n" + GetCodeIndentation(1) + listItem;
|
|
}
|
|
}
|
|
|
|
foreach (KeyValuePair<string, List<string>> dictItem in _duplicateConstants)
|
|
{
|
|
if (!firstLineInFileAllocated)
|
|
firstLineInFileAllocated = true;
|
|
else
|
|
textToBeWrittenToFile += "\r\n\r\n";
|
|
|
|
textToBeWrittenToFile += "Duplicate definition for constant \"" + dictItem.Key + "\" found in the following files: ";
|
|
foreach (string listItem in dictItem.Value)
|
|
{
|
|
textToBeWrittenToFile += "\r\n" + GetCodeIndentation(1) + listItem;
|
|
}
|
|
}
|
|
|
|
if (textToBeWrittenToFile.Length > 0)
|
|
{
|
|
try
|
|
{
|
|
fs = new FileStream(diagnosticFile, FileMode.Create, FileAccess.ReadWrite);
|
|
writer = new StreamWriter(fs, Encoding.Default);
|
|
writer.Write(textToBeWrittenToFile);
|
|
}
|
|
catch (System.Exception ex)
|
|
{
|
|
_logger.Error(ex);
|
|
isSuccessful = false;
|
|
}
|
|
finally
|
|
{
|
|
if (writer != null)
|
|
{
|
|
writer.Close();
|
|
fs.Close();
|
|
}
|
|
}
|
|
}
|
|
|
|
//m_mainWindow.updateStatusBox("DONE\n");
|
|
}
|
|
|
|
return isSuccessful;
|
|
}
|
|
public static string GetCodeIndentation(int indentMultiples)
|
|
{
|
|
string indentUnit = " ";
|
|
string indentation = string.Empty;
|
|
|
|
for (int i = 1; i <= indentMultiples; i++)
|
|
indentation += indentUnit;
|
|
|
|
return indentation;
|
|
}
|
|
}
|
|
|
|
}
|