Files
GenericTeProgramLibrary/Source/TSRealLib/HAL/Implementations/BIT/COEComm/XmlUtilities/XmlMbitParser.cs
2025-03-13 12:04:22 -07:00

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;
}
}
}