diff --git a/HashingCmd/HashingCmd.csproj b/HashingCmd/HashingCmd.csproj index ec77475b5e1d27daccf5e9a1ded6325072c8c14b..7ee07480a160366124db4c0ab30057e323729952 100644 --- a/HashingCmd/HashingCmd.csproj +++ b/HashingCmd/HashingCmd.csproj @@ -60,10 +60,18 @@ <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" /> </ItemGroup> <ItemGroup> + <ProjectReference Include="..\VectoCommon\VectoCommon\VectoCommon.csproj"> + <Project>{79A066AD-69A9-4223-90F6-6ED5D2D084F4}</Project> + <Name>VectoCommon</Name> + </ProjectReference> <ProjectReference Include="..\VectoCommon\VectoHashing\VectoHashing.csproj"> <Project>{B673E12F-D323-4C4C-8805-9915B2C72D3D}</Project> <Name>VectoHashing</Name> </ProjectReference> + <ProjectReference Include="..\VectoCore\VectoCore\VectoCore.csproj"> + <Project>{CD36938A-ADD9-4C65-96DA-B397CDEEA90A}</Project> + <Name>VectoCore</Name> + </ProjectReference> </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <!-- To modify your build process, add your task inside one of the targets below and uncomment it. diff --git a/HashingCmd/Program.cs b/HashingCmd/Program.cs index a9a57e21017aaad337588063400894bb6a02599e..d76254fff24bcdaf45b6b388eb9fce14bfcb6c2c 100644 --- a/HashingCmd/Program.cs +++ b/HashingCmd/Program.cs @@ -7,6 +7,12 @@ using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; using System.Xml; +using System.Xml.Linq; +using System.Xml.Schema; +using System.Xml.XPath; +using TUGraz.VectoCommon.Exceptions; +using TUGraz.VectoCore.InputData.FileIO.XML.Declaration; +using TUGraz.VectoCore.Utils; using TUGraz.VectoHashing; namespace HashingCmd @@ -16,22 +22,26 @@ namespace HashingCmd public delegate void HashingAction(string filename, VectoHash h); private const string Usage = @" -hashingcmd.exe -v <file.xml> +hashingcmd.exe (-h | [-v] [[-s] -x] [-c] [-r]) <file.xml> <file2.xml> <file3.xml> "; private const string Help = @" hashingcmd.exe --h: help +-h: print help -v: verify hashed file --s: create hashed file file +-s: create hashed file +-x: validate generated XML against VECTO XML schema -c: compute hash and write to stdout -r: read hash from file and write to stdout "; static Dictionary<string, HashingAction> actions = new Dictionary<string, HashingAction>(); + static bool _validateXML = false; + private static bool xmlValid = true; + static int Main(string[] args) { try { @@ -45,7 +55,16 @@ hashingcmd.exe actions["-r"] = ReadHashAction; actions["-s"] = CreateHashedFileAction; - var fileList = args.Except(actions.Keys); + if (args.Contains("-x")) { + _validateXML = true; + } + + var fileList = args.Except(actions.Keys.Concat(new[] { "-x" })).ToArray(); + if (fileList.Length == 0 || !args.Intersect(actions.Keys.ToArray()).Any()) { + ShowVersionInformation(); + Console.Write(Usage); + return 0; + } foreach (var file in fileList) { WriteLine("processing " + Path.GetFileName(file)); if (!File.Exists(Path.GetFullPath(file))) { @@ -60,6 +79,9 @@ hashingcmd.exe } catch (Exception e) { Console.ForegroundColor = ConsoleColor.Red; Console.Error.WriteLine(e.Message); + if (e.InnerException != null) { + Console.Error.WriteLine(e.InnerException.Message); + } Console.ResetColor(); } } @@ -101,6 +123,65 @@ hashingcmd.exe result.WriteTo(writer); writer.Flush(); writer.Close(); + + if (_validateXML) { + ValidateXML(destination); + } + } + + private static void ValidateXML(string filename) + { + try { + var settings = new XmlReaderSettings { + ValidationType = ValidationType.Schema, + ValidationFlags = //XmlSchemaValidationFlags.ProcessInlineSchema | + //XmlSchemaValidationFlags.ProcessSchemaLocation | + XmlSchemaValidationFlags.ReportValidationWarnings + }; + settings.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack); + settings.Schemas.Add(GetXMLSchema("")); + + var vreader = XmlReader.Create(filename, settings); + var doc = new XmlDocument(); + doc.Load(vreader); + doc.Validate(ValidationCallBack); + //while (vreader.Read()) { + // Console.WriteLine(vreader.Value); + //} + if (xmlValid) { + WriteLine("Valid", ConsoleColor.Green); + } + } catch (Exception e) { + Console.ForegroundColor = ConsoleColor.Red; + Console.Error.WriteLine("Failed to validate hashed XML file!"); + Console.Error.WriteLine(e.Message); + if (e.InnerException != null) { + Console.Error.WriteLine(e.InnerException.Message); + } + Console.ResetColor(); + } + } + + private static void ValidationCallBack(object sender, ValidationEventArgs args) + { + xmlValid = false; + if (args.Severity == XmlSeverityType.Error) { + throw new Exception(string.Format("Validation error: {0}" + Environment.NewLine + + "Line: {1}", args.Message, args.Exception.LineNumber)); + } else { + Console.Error.WriteLine(string.Format("Validation warning: {0}" + Environment.NewLine + + "Line: {1}", args.Message, args.Exception.LineNumber)); + } + } + + private static XmlSchemaSet GetXMLSchema(string version) + { + var resource = RessourceHelper.LoadResourceAsStream(RessourceHelper.ResourceType.XMLSchema, "VectoComponent.xsd"); + var xset = new XmlSchemaSet() { XmlResolver = new XmlResourceResolver() }; + var reader = XmlReader.Create(resource, new XmlReaderSettings(), "schema://"); + xset.Add(XmlSchema.Read(reader, null)); + xset.Compile(); + return xset; } private static void ReadHashAction(string filename, VectoHash h) @@ -115,7 +196,7 @@ hashingcmd.exe } for (var i = 0; i < component.Count; i++) { var readHash = h.ReadHash(component.Entry, i); - WriteLine(" " + component.Entry.XMLElementName() + "\t ... >" + readHash + "<"); + WriteLine(" " + component.Entry.XMLElementName() + "\t ... " + readHash + ""); } } } @@ -135,14 +216,14 @@ hashingcmd.exe } for (var i = 0; i < component.Count; i++) { var computedHash = h.ComputeHash(component.Entry, i); - WriteLine(" " + component.Entry.XMLElementName() + "\t ... >" + computedHash + "<"); + WriteLine(" " + component.Entry.XMLElementName() + "\t ... " + computedHash + ""); } } var jobHash = h.ComputeHash(); - WriteLine(" job file\t ... >" + jobHash + "<"); + WriteLine(" job file\t ... " + jobHash + ""); } else { var hash = h.ComputeHash(); - WriteLine(" computed hash: >" + hash + "<"); + WriteLine(" computed hash: " + hash + ""); } } diff --git a/VectoCommon/VectoHashing/Resources/XSLT/SortInputData.xslt b/VectoCommon/VectoHashing/Resources/XSLT/SortInputData.xslt index 1247151435447af97fb355b947040324b3e09e97..b77bd20244a953a7737e1333cc874e192fdb2d31 100644 --- a/VectoCommon/VectoHashing/Resources/XSLT/SortInputData.xslt +++ b/VectoCommon/VectoHashing/Resources/XSLT/SortInputData.xslt @@ -31,6 +31,7 @@ </xsl:template> <xsl:template match="*[local-name()='FuelConsumptionMap']"> <xsl:element name="{local-name()}"> + <xsl:apply-templates select="@*"/> <xsl:for-each select="*"> <xsl:sort data-type="number" select="@engineSpeed" order="ascending"/> <xsl:sort data-type="number" select="@torque" order="ascending"/> @@ -40,6 +41,7 @@ </xsl:template> <xsl:template match="*[local-name()='FullLoadAndDragCurve']"> <xsl:element name="{local-name()}"> + <xsl:apply-templates select="@*"/> <xsl:for-each select="*"> <xsl:sort data-type="number" select="@engineSpeed" order="ascending"/> <xsl:apply-templates select="."/> @@ -48,6 +50,7 @@ </xsl:template> <xsl:template match="*[local-name()='TorqueLossMap']"> <xsl:element name="{local-name()}"> + <xsl:apply-templates select="@*"/> <xsl:for-each select="*"> <xsl:sort data-type="number" select="@inputSpeed" order="ascending"/> <xsl:sort data-type="number" select="@inputTorque" order="ascending"/> @@ -57,6 +60,7 @@ </xsl:template> <xsl:template match="*[local-name()='RetarderLossMap']"> <xsl:element name="{local-name()}"> + <xsl:apply-templates select="@*"/> <xsl:for-each select="*"> <xsl:sort data-type="number" select="@retarderSpeed" order="ascending"/> <xsl:apply-templates select="."/> @@ -65,6 +69,7 @@ </xsl:template> <xsl:template match="*[local-name()='TorqueLimits']"> <xsl:element name="{local-name()}"> + <xsl:apply-templates select="@*"/> <xsl:for-each select="*"> <xsl:sort data-type="number" select="@gear" order="ascending"/> <xsl:apply-templates select="."/> @@ -73,6 +78,7 @@ </xsl:template> <xsl:template match="*[local-name()='Gears']"> <xsl:element name="{local-name()}"> + <xsl:apply-templates select="@*"/> <xsl:for-each select="*"> <xsl:sort data-type="number" select="@number" order="ascending"/> <xsl:apply-templates select="."/> @@ -81,6 +87,7 @@ </xsl:template> <xsl:template match="*[local-name()='Characteristics']"> <xsl:element name="{local-name()}"> + <xsl:apply-templates select="@*"/> <xsl:for-each select="*"> <xsl:sort data-type="number" select="@speedRatio" order="ascending"/> <xsl:apply-templates select="."/> @@ -88,6 +95,7 @@ </xsl:element> </xsl:template> <xsl:template match="*[local-name()='Axles']"> + <xsl:apply-templates select="@*"/> <xsl:element name="{local-name()}"> <xsl:for-each select="*"> <xsl:sort data-type="number" select="@axleNumber" order="ascending"/> diff --git a/VectoCommon/VectoHashing/VectoHash.cs b/VectoCommon/VectoHashing/VectoHash.cs index 4ba0be427e5e8aea5c1bc96f2a0c62e591b8b19a..ef31b0c15028f9962dc7e4f222b932a08832aebd 100644 --- a/VectoCommon/VectoHashing/VectoHash.cs +++ b/VectoCommon/VectoHashing/VectoHash.cs @@ -19,14 +19,22 @@ namespace TUGraz.VectoHashing public static VectoHash Load(string filename) { var doc = new XmlDocument(); - doc.Load(new XmlTextReader(filename)); + try { + doc.Load(new XmlTextReader(filename)); + } catch (Exception e) { + throw new Exception("failed to read XML document", e); + } return new VectoHash(doc); } public static VectoHash Load(Stream stream) { var doc = new XmlDocument(); - doc.Load(new XmlTextReader(stream)); + try { + doc.Load(new XmlTextReader(stream)); + } catch (Exception e) { + throw new Exception("failed to read XML document", e); + } return new VectoHash(doc); } @@ -77,12 +85,15 @@ namespace TUGraz.VectoHashing if (components.Count > 1) { throw new Exception("input must not contain multiple components!"); } - var query = string.Format("//*[local-name()='{0}']/*[local-name()='Data']", components[0]); + if (components.Count == 0) { + throw new Exception("input does not contain a known component!"); + } + var query = string.Format("//*[local-name()='{0}']/*[local-name()='Data']", components[0].XMLElementName()); var node = Document.SelectSingleNode(query); if (node == null) { - throw new Exception(string.Format("'Data' element for component '{0}' not found!", components[0])); + throw new Exception(string.Format("'Data' element for component '{0}' not found!", components[0].XMLElementName())); } - query = string.Format("//*[local-name()='{0}']/*[local-name()='Signature']", components[0]); + query = string.Format("//*[local-name()='{0}']/*[local-name()='Signature']", components[0].XMLElementName()); var sigNodes = Document.SelectNodes(query); if (sigNodes != null && sigNodes.Count > 0) { throw new Exception("input data already contains a signature element"); @@ -160,8 +171,15 @@ namespace TUGraz.VectoHashing private static string GetHashValue(XmlDocument hashed, string elementToHash) { - var node = hashed.SelectSingleNode("//*[@URI='#" + elementToHash + "']/*[local-name() = 'DigestValue']"); - return node == null ? null : node.InnerText; + //var node = hashed.SelectSingleNode("//*[@URI='#" + elementToHash + "']/*[local-name() = 'DigestValue']"); + var nodes = hashed.SelectNodes("//*[@URI='#" + elementToHash + "']/*[local-name() = 'DigestValue']"); + if (nodes == null || nodes.Count == 0) { + return null; + } + if (nodes.Count > 1) { + throw new Exception("Multiple DigestValue elements found!"); + } + return nodes[0].InnerText; } } } \ No newline at end of file