From 497cb1401ea82c3d0ed3402ae5d44fb05ea0a96d Mon Sep 17 00:00:00 2001
From: Markus Quaritsch <markus.quaritsch@tugraz.at>
Date: Fri, 1 Sep 2017 15:54:19 +0200
Subject: [PATCH] more work on hashing screen, adding icons etc.

---
 HashingTool/App.xaml                          |  10 +-
 HashingTool/HashingTool.csproj                |  33 +++-
 HashingTool/Helper/CollectionConverter.cs     |  33 ++++
 HashingTool/Helper/IOService.cs               |  45 ++++++
 HashingTool/Resources/Icon_NOK.xaml           |  14 ++
 HashingTool/Resources/Icon_OK.xaml            |  17 +++
 HashingTool/Resources/Icon_XML_NOK.xaml       |  20 +++
 HashingTool/Resources/Icon_XML_OK.xaml        |  20 +++
 HashingTool/Resources/Icon_XML_unknown.xaml   |  19 +++
 HashingTool/Util/XMLValidator.cs              |  75 +++++++++
 .../ViewModel/HashComponentDataViewModel.cs   |  97 ++++++------
 HashingTool/ViewModel/UserControl/XMLFile.cs  | 125 +++++++++++++++
 HashingTool/Views/HashComponentData.xaml      |  90 +++++++++--
 .../UserControl/VectoXMLFileSelector.xaml     |  37 +++++
 .../UserControl/VectoXMLFileSelector.xaml.cs  |  41 +++++
 .../Impl/XmlDsigVectoTransform.cs             | 142 +++++++++---------
 16 files changed, 676 insertions(+), 142 deletions(-)
 create mode 100644 HashingTool/Helper/CollectionConverter.cs
 create mode 100644 HashingTool/Helper/IOService.cs
 create mode 100644 HashingTool/Resources/Icon_NOK.xaml
 create mode 100644 HashingTool/Resources/Icon_OK.xaml
 create mode 100644 HashingTool/Resources/Icon_XML_NOK.xaml
 create mode 100644 HashingTool/Resources/Icon_XML_OK.xaml
 create mode 100644 HashingTool/Resources/Icon_XML_unknown.xaml
 create mode 100644 HashingTool/Util/XMLValidator.cs
 create mode 100644 HashingTool/ViewModel/UserControl/XMLFile.cs
 create mode 100644 HashingTool/Views/UserControl/VectoXMLFileSelector.xaml
 create mode 100644 HashingTool/Views/UserControl/VectoXMLFileSelector.xaml.cs

diff --git a/HashingTool/App.xaml b/HashingTool/App.xaml
index 422c404afc..5f3d51229e 100644
--- a/HashingTool/App.xaml
+++ b/HashingTool/App.xaml
@@ -2,6 +2,14 @@
 			xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 			xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
 	<Application.Resources>
-
+		<ResourceDictionary>
+			<ResourceDictionary.MergedDictionaries>
+				<ResourceDictionary Source="Resources/Icon_XML_unknown.xaml" />
+				<ResourceDictionary Source="Resources/Icon_XML_OK.xaml" />
+				<ResourceDictionary Source="Resources/Icon_XML_NOK.xaml" />
+				<ResourceDictionary Source="Resources/Icon_OK.xaml" />
+				<ResourceDictionary Source="Resources/Icon_NOK.xaml" />
+			</ResourceDictionary.MergedDictionaries>
+		</ResourceDictionary>
 	</Application.Resources>
 </Application>
\ No newline at end of file
diff --git a/HashingTool/HashingTool.csproj b/HashingTool/HashingTool.csproj
index 7e8a498dba..39deab7488 100644
--- a/HashingTool/HashingTool.csproj
+++ b/HashingTool/HashingTool.csproj
@@ -63,9 +63,8 @@
       <Generator>MSBuild:Compile</Generator>
       <SubType>Designer</SubType>
     </ApplicationDefinition>
-    <Compile Include="Helper\BoolViewConverter.cs" />
+    <Compile Include="Helper\CollectionConverter.cs" />
     <Compile Include="Helper\IOService.cs" />
-    <Compile Include="Model\TestModel.cs" />
     <Compile Include="Properties\Annotations.cs" />
     <Compile Include="Properties\Version.cs">
       <DependentUpon>Version.tt</DependentUpon>
@@ -79,13 +78,17 @@
     <Compile Include="ViewModel\RelayCommand.cs" />
     <Compile Include="ViewModel\HashComponentDataViewModel.cs" />
     <Compile Include="ViewModel\VerifyInputDataViewModel.cs" />
-    <Compile Include="ViewModel\XMLValidator.cs" />
+    <Compile Include="ViewModel\UserControl\XMLFile.cs" />
+    <Compile Include="Util\XMLValidator.cs" />
     <Compile Include="Views\HashComponentData.xaml.cs">
       <DependentUpon>HashComponentData.xaml</DependentUpon>
     </Compile>
     <Compile Include="Views\HomeView.xaml.cs">
       <DependentUpon>HomeView.xaml</DependentUpon>
     </Compile>
+    <Compile Include="Views\UserControl\VectoXMLFileSelector.xaml.cs">
+      <DependentUpon>VectoXMLFileSelector.xaml</DependentUpon>
+    </Compile>
     <Compile Include="Views\VerifyInputData.xaml.cs">
       <DependentUpon>VerifyInputData.xaml</DependentUpon>
     </Compile>
@@ -101,6 +104,26 @@
       <DependentUpon>MainWindow.xaml</DependentUpon>
       <SubType>Code</SubType>
     </Compile>
+    <Page Include="Resources\Icon_NOK.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:Compile</Generator>
+    </Page>
+    <Page Include="Resources\Icon_OK.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:Compile</Generator>
+    </Page>
+    <Page Include="Resources\Icon_XML_NOK.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:Compile</Generator>
+    </Page>
+    <Page Include="Resources\Icon_XML_OK.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:Compile</Generator>
+    </Page>
+    <Page Include="Resources\Icon_XML_unknown.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:Compile</Generator>
+    </Page>
     <Page Include="Views\HashComponentData.xaml">
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>
@@ -109,6 +132,10 @@
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>
     </Page>
+    <Page Include="Views\UserControl\VectoXMLFileSelector.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:Compile</Generator>
+    </Page>
     <Page Include="Views\VerifyInputData.xaml">
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>
diff --git a/HashingTool/Helper/CollectionConverter.cs b/HashingTool/Helper/CollectionConverter.cs
new file mode 100644
index 0000000000..78f1fd749c
--- /dev/null
+++ b/HashingTool/Helper/CollectionConverter.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Collections;
+using System.Globalization;
+using System.Linq;
+using System.Windows.Data;
+
+namespace HashingTool.Helper
+{
+	public class CollectionConverter : IValueConverter
+	{
+		public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+		{
+			var val = value as ICollection;
+			if (val == null) {
+				throw new ArgumentException("can only convert collections!");
+			}
+			if (targetType == typeof(object) || targetType == typeof(string)) {
+				var tmp = new string[val.Count];
+				var i = 0;
+				foreach (var entry in val) {
+					tmp[i++] = entry.ToString();
+				}
+				return string.Join(", ", tmp);
+			}
+			throw new ArgumentException("Unhandled target type");
+		}
+
+		public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+		{
+			throw new NotImplementedException();
+		}
+	}
+}
diff --git a/HashingTool/Helper/IOService.cs b/HashingTool/Helper/IOService.cs
new file mode 100644
index 0000000000..b6880184f2
--- /dev/null
+++ b/HashingTool/Helper/IOService.cs
@@ -0,0 +1,45 @@
+using System.IO;
+using Microsoft.Win32;
+
+namespace HashingTool.Helper
+{
+	public interface IOService
+	{
+		Stream OpenFileDialog(string defaultPath, string defaultExt, string filter, out string location);
+
+		Stream SaveData(string defaultPath, string defaultExt, string filter, out string location);
+	}
+
+	public class WPFIoService : IOService
+	{
+		public Stream OpenFileDialog(string defaultPath, string defaultExt, string filter, out string location)
+		{
+			var dlg = new OpenFileDialog {
+				DefaultExt = defaultExt,
+				Filter = filter
+			};
+			var result = dlg.ShowDialog();
+			if (result != true) {
+				location = null;
+				return null;
+			}
+			location = dlg.FileName;
+			return File.OpenRead(dlg.FileName);
+		}
+
+		public Stream SaveData(string defaultPath, string defaultExt, string filter, out string location)
+		{
+			var dlg = new SaveFileDialog() {
+				DefaultExt = defaultExt,
+				Filter = filter
+			};
+			var result = dlg.ShowDialog();
+			if (result != true) {
+				location = null;
+				return null;
+			}
+			location = dlg.FileName;
+			return new FileStream(dlg.FileName, FileMode.Create);
+		}
+	}
+}
diff --git a/HashingTool/Resources/Icon_NOK.xaml b/HashingTool/Resources/Icon_NOK.xaml
new file mode 100644
index 0000000000..f9774db2bf
--- /dev/null
+++ b/HashingTool/Resources/Icon_NOK.xaml
@@ -0,0 +1,14 @@
+<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+					xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+	<Canvas x:Key="Icon_NOK" Name="layer1">
+		<Canvas.RenderTransform>
+			<TranslateTransform X="-66.503906" Y="-580.23275" />
+		</Canvas.RenderTransform>
+		<Canvas Name="flowRoot4806" Opacity="1">
+			<Path Name="path4841" Fill="#FFEB0000" StrokeThickness="1" StrokeLineJoin="Miter" StrokeStartLineCap="Flat"
+				StrokeEndLineCap="Flat"
+				Data="m 87.37793 608.62141 -1.098633 1.40625 q -8.217774 10.76661 -12.788086 10.76661 -3.427734 0 -6.987305 -5.625 1.230469 0.26367 1.889649 0.26367 5.756836 0 13.095703 -9.44824 l 1.713867 -2.15332 -1.230469 -1.49415 q -8.876953 -10.32714 -8.876953 -14.50195 0 -2.98828 4.833984 -7.60254 2.021485 9.05274 8.4375 17.09473 l 0.966797 1.23047 1.845703 -2.24121 q 9.052735 -11.20606 14.414063 -11.20606 2.63672 0 4.35059 2.59278 0.30761 0.43945 0.8789 1.23046 -6.81152 3.07618 -15.249021 12.43653 l -1.801758 2.02148 1.318359 1.4502 q 7.99805 8.78906 14.76563 8.78906 1.97753 0 3.6914 -0.43945 -2.19726 4.57031 -3.6914 5.97656 -1.4502 1.40625 -3.99903 1.40625 -5.537108 0 -14.414061 -9.71191 l -2.065429 -2.24122 z" />
+		</Canvas>
+
+	</Canvas>
+</ResourceDictionary>
\ No newline at end of file
diff --git a/HashingTool/Resources/Icon_OK.xaml b/HashingTool/Resources/Icon_OK.xaml
new file mode 100644
index 0000000000..731e0a8151
--- /dev/null
+++ b/HashingTool/Resources/Icon_OK.xaml
@@ -0,0 +1,17 @@
+<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+					xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+	<Canvas x:Key="Icon_OK" Name="layer1">
+		<Canvas.RenderTransform>
+			<TranslateTransform X="-55.706613" Y="-712.36918" />
+		</Canvas.RenderTransform>
+
+		<Canvas Name="flowRoot48069" Opacity="1">
+			<Canvas.RenderTransform>
+				<TranslateTransform X="-5.7972934" Y="86.067101" />
+			</Canvas.RenderTransform>
+			<Path Name="path4844" Fill="#FF00A500" StrokeThickness="1"
+				StrokeLineJoin="Miter" StrokeStartLineCap="Flat" StrokeEndLineCap="Flat"
+				Data="m 119.33594 626.30208 1.31836 2.28515 q -12.87598 9.09668 -23.862308 23.02735 -10.986328 13.93066 -15.864258 27.29004 l -1.933593 1.27441 q -2.504883 1.62598 -4.306641 3.25195 -0.307617 -1.58203 -1.713867 -5.09765 l -1.010742 -2.50488 q -3.295899 -8.12989 -5.581055 -11.33789 -2.241211 -3.25196 -4.87793 -3.51563 3.559571 -3.25195 6.196289 -3.25195 3.647461 0 7.998047 9.7998 l 1.582031 3.51563 q 7.778321 -13.93067 18.764649 -25.66407 11.030278 -11.73339 23.291018 -19.07226 z" />
+		</Canvas>
+	</Canvas>
+</ResourceDictionary>
\ No newline at end of file
diff --git a/HashingTool/Resources/Icon_XML_NOK.xaml b/HashingTool/Resources/Icon_XML_NOK.xaml
new file mode 100644
index 0000000000..ae1f9ee1e7
--- /dev/null
+++ b/HashingTool/Resources/Icon_XML_NOK.xaml
@@ -0,0 +1,20 @@
+<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+
+	<Canvas x:Key="Icon_XML_NOK">
+		<Canvas.RenderTransform>
+			<TranslateTransform X="-59.285156" Y="-215.2361" />
+		</Canvas.RenderTransform>
+		<Canvas Name="flowRoot4136" Opacity="1">
+			<Path Name="path4145" Fill="#FFFF0000" StrokeThickness="1" StrokeLineJoin="Miter" StrokeStartLineCap="Flat"
+					StrokeEndLineCap="Flat"
+					Data="m 59.285156 243.86892 9.785156 -14.94141 -8.867187 -13.69141 6.757812 0 5.742188 9.19922 5.625 -9.19922 6.699219 0 -8.90625 13.90625 9.785156 14.72657 -6.972656 0 -6.347657 -9.90235 -6.367187 9.90235 -6.933594 0 z" />
+			<Path Name="path4147" Fill="#FFFF0000" StrokeThickness="1" StrokeLineJoin="Miter" StrokeStartLineCap="Flat"
+					StrokeEndLineCap="Flat"
+					Data="m 88.835937 243.86892 0 -28.63282 8.652344 0 5.195309 19.53125 5.13672 -19.53125 8.67188 0 0 28.63282 -5.3711 0 0 -22.53907 -5.68359 22.53907 -5.566406 0 -5.664063 -22.53907 0 22.53907 -5.371094 0 z" />
+			<Path Name="path4149" Fill="#FFFF0000" StrokeThickness="1" StrokeLineJoin="Miter" StrokeStartLineCap="Flat"
+					StrokeEndLineCap="Flat"
+					Data="m 122.42969 243.86892 0 -28.39844 5.78125 0 0 23.57422 14.375 0 0 4.82422 -20.15625 0 z" />
+		</Canvas>
+	</Canvas>
+</ResourceDictionary>
\ No newline at end of file
diff --git a/HashingTool/Resources/Icon_XML_OK.xaml b/HashingTool/Resources/Icon_XML_OK.xaml
new file mode 100644
index 0000000000..c863cfa188
--- /dev/null
+++ b/HashingTool/Resources/Icon_XML_OK.xaml
@@ -0,0 +1,20 @@
+<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+					xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+
+	<Canvas x:Key="Icon_XML_OK">
+		<Canvas.RenderTransform>
+			<TranslateTransform X="-59.285156" Y="-215.2361" />
+		</Canvas.RenderTransform>
+		<Canvas Name="flowRoot4136" Opacity="1">
+			<Path Name="path4145" Fill="#FF00C000" StrokeThickness="1" StrokeLineJoin="Miter" StrokeStartLineCap="Flat"
+				StrokeEndLineCap="Flat"
+				Data="m 59.285156 243.86892 9.785156 -14.94141 -8.867187 -13.69141 6.757812 0 5.742188 9.19922 5.625 -9.19922 6.699219 0 -8.90625 13.90625 9.785156 14.72657 -6.972656 0 -6.347657 -9.90235 -6.367187 9.90235 -6.933594 0 z" />
+			<Path Name="path4147" Fill="#FF00C000" StrokeThickness="1" StrokeLineJoin="Miter" StrokeStartLineCap="Flat"
+				StrokeEndLineCap="Flat"
+				Data="m 88.835937 243.86892 0 -28.63282 8.652344 0 5.195309 19.53125 5.13672 -19.53125 8.67188 0 0 28.63282 -5.3711 0 0 -22.53907 -5.68359 22.53907 -5.566406 0 -5.664063 -22.53907 0 22.53907 -5.371094 0 z" />
+			<Path Name="path4149" Fill="#FF00C000" StrokeThickness="1" StrokeLineJoin="Miter" StrokeStartLineCap="Flat"
+				StrokeEndLineCap="Flat"
+				Data="m 122.42969 243.86892 0 -28.39844 5.78125 0 0 23.57422 14.375 0 0 4.82422 -20.15625 0 z" />
+		</Canvas>
+	</Canvas>
+</ResourceDictionary>
\ No newline at end of file
diff --git a/HashingTool/Resources/Icon_XML_unknown.xaml b/HashingTool/Resources/Icon_XML_unknown.xaml
new file mode 100644
index 0000000000..92d81c29df
--- /dev/null
+++ b/HashingTool/Resources/Icon_XML_unknown.xaml
@@ -0,0 +1,19 @@
+<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+					xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+	<Canvas x:Key="ICON_XML_unknown" Name="layer1">
+		<Canvas.RenderTransform>
+			<TranslateTransform X="-59.285156" Y="-215.2361" />
+		</Canvas.RenderTransform>
+		<Canvas Name="flowRoot4136" Opacity="1">
+			<Path Name="path4145" StrokeThickness="1" Stroke="#FF464646" StrokeLineJoin="Miter" StrokeStartLineCap="Flat"
+				StrokeEndLineCap="Flat"
+				Data="m 59.285156 243.86892 9.785156 -14.94141 -8.867187 -13.69141 6.757812 0 5.742188 9.19922 5.625 -9.19922 6.699219 0 -8.90625 13.90625 9.785156 14.72657 -6.972656 0 -6.347657 -9.90235 -6.367187 9.90235 -6.933594 0 z" />
+			<Path Name="path4147" StrokeThickness="1" Stroke="#FF464646" StrokeLineJoin="Miter" StrokeStartLineCap="Flat"
+				StrokeEndLineCap="Flat"
+				Data="m 88.835937 243.86892 0 -28.63282 8.652344 0 5.195309 19.53125 5.13672 -19.53125 8.67188 0 0 28.63282 -5.3711 0 0 -22.53907 -5.68359 22.53907 -5.566406 0 -5.664063 -22.53907 0 22.53907 -5.371094 0 z" />
+			<Path Name="path4149" StrokeThickness="1" Stroke="#FF464646" StrokeLineJoin="Miter" StrokeStartLineCap="Flat"
+				StrokeEndLineCap="Flat"
+				Data="m 122.42969 243.86892 0 -28.39844 5.78125 0 0 23.57422 14.375 0 0 4.82422 -20.15625 0 z" />
+		</Canvas>
+	</Canvas>
+</ResourceDictionary>
\ No newline at end of file
diff --git a/HashingTool/Util/XMLValidator.cs b/HashingTool/Util/XMLValidator.cs
new file mode 100644
index 0000000000..da85aa7d5d
--- /dev/null
+++ b/HashingTool/Util/XMLValidator.cs
@@ -0,0 +1,75 @@
+using System;
+using System.Threading.Tasks;
+using System.Xml;
+using System.Xml.Schema;
+using TUGraz.VectoCore.Utils;
+
+namespace HashingTool.Util
+{
+	public class XMLValidator
+	{
+		private readonly Action<XmlSeverityType, ValidationEvent> _validationErrorAction;
+		private readonly Action<bool> _resultAction;
+		private bool _valid;
+
+		public XMLValidator(Action<bool> resultaction, Action<XmlSeverityType, ValidationEvent> validationErrorAction)
+		{
+			_validationErrorAction = validationErrorAction ?? ((x, y) => { });
+			_resultAction = resultaction ?? (x => { });
+			_valid = false;
+		}
+
+		public Task<bool> ValidateXML(XmlReader hashedComponent)
+		{
+			var task = new Task<bool>(() => DoValidation(hashedComponent));
+			task.Start();
+			return task;
+		}
+
+		private bool DoValidation(XmlReader hashedComponent)
+		{
+			_valid = true;
+			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(hashedComponent, settings);
+				var doc = new XmlDocument();
+				doc.Load(vreader);
+				doc.Validate(ValidationCallBack);
+			} catch (Exception e) {
+				_validationErrorAction(XmlSeverityType.Error, new ValidationEvent() { Exception = e });
+			}
+			return _valid;
+		}
+
+		private void ValidationCallBack(object sender, ValidationEventArgs args)
+		{
+			_resultAction(false);
+			_valid = false;
+			_validationErrorAction(args.Severity, new ValidationEvent { ValidationEventArgs = args });
+		}
+
+		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;
+		}
+	}
+
+	public class ValidationEvent
+	{
+		public Exception Exception;
+		public ValidationEventArgs ValidationEventArgs;
+	}
+}
diff --git a/HashingTool/ViewModel/HashComponentDataViewModel.cs b/HashingTool/ViewModel/HashComponentDataViewModel.cs
index 0b84ba4644..da4ea95c71 100644
--- a/HashingTool/ViewModel/HashComponentDataViewModel.cs
+++ b/HashingTool/ViewModel/HashComponentDataViewModel.cs
@@ -1,6 +1,7 @@
 using System;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
+using System.ComponentModel;
 using System.IO;
 using System.Text;
 using System.Threading.Tasks;
@@ -10,6 +11,8 @@ using System.Xml;
 using System.Xml.Linq;
 using System.Xml.Schema;
 using HashingTool.Helper;
+using HashingTool.Util;
+using HashingTool.ViewModel.UserControl;
 using TUGraz.VectoCore.Utils;
 using TUGraz.VectoHashing;
 
@@ -18,23 +21,36 @@ namespace HashingTool.ViewModel
 	public class HashComponentDataViewModel : ObservableObject, IMainView
 	{
 		private readonly ApplicationViewModel _applicationViewModel;
-		private bool? _componentDataValid;
 		private string _digestValue;
-		//private ObservableCollection<string> _xmlValidationErrors = new ObservableCollection<string>();
-		private Stream _stream;
+
 		private XDocument _result;
 
-		private IOService _ioService = new WPFIoService();
-		private RelayCommand _saveCommand;
+		private readonly IOService _ioService = new WPFIoService();
+		private readonly RelayCommand _saveCommand;
 		private bool _busy;
-		private string _source;
+		private XMLFile _sourceFile;
+		private bool? _componentDataValid;
 
 		public HashComponentDataViewModel()
 		{
 			XMLValidationErrors = new ObservableCollection<string>();
+			_sourceFile = new XMLFile(_ioService, false);
+			_sourceFile.PropertyChanged += SourceChanged;
 			_saveCommand = new RelayCommand(SaveDocument,
 				() => !_busy && ComponentDataValid != null && ComponentDataValid.Value && _result != null);
 			_busy = false;
+
+			CanonicalizaitionMethods = new ObservableCollection<string>() {
+				"urn:vecto:xml:2017:canonicalization",
+				"http://www.w3.org/2001/10/xml-exc-c14n#"
+			};
+		}
+
+		private void SourceChanged(object sender, PropertyChangedEventArgs e)
+		{
+			if (e.PropertyName == "Document") {
+				DoComputeHash();
+			}
 		}
 
 		public HashComponentDataViewModel(ApplicationViewModel applicationViewModel) : this()
@@ -52,38 +68,15 @@ namespace HashingTool.ViewModel
 			get { return ApplicationViewModel.HomeView; }
 		}
 
-		public string Source
+		public XMLFile ComponentFile
 		{
-			get { return _source; }
-			private set {
-				if (_source == value) {
-					return;
-				}
-				_source = value;
-				RaisePropertyChanged("Source");
-			}
+			get { return _sourceFile; }
+			private set { _sourceFile = value; }
 		}
 
-		public bool? ComponentDataValid
-		{
-			get { return _componentDataValid; }
-			private set {
-				if (_componentDataValid == value) {
-					return;
-				}
-				_componentDataValid = value;
-				RaisePropertyChanged("ComponentDataValid");
-			}
-		}
 
 		public ObservableCollection<string> XMLValidationErrors { get; set; }
-		//{
-		//	get { return _xmlValidationErrors; }
-		//	private set {
-		//		_xmlValidationErrors = value;
-		//		RaisePropertyChanged("XMLValidationErrors");
-		//	}
-		//}
+
 
 		public string DigestValue
 		{
@@ -97,11 +90,6 @@ namespace HashingTool.ViewModel
 			}
 		}
 
-		public ICommand SetComponentData
-		{
-			get { return new RelayCommand(HashComponentData, () => !_busy); }
-		}
-
 		public ICommand SaveHashedDocument
 		{
 			get { return _saveCommand; }
@@ -124,28 +112,29 @@ namespace HashingTool.ViewModel
 			}
 		}
 
-		private void HashComponentData()
+		public bool? ComponentDataValid
 		{
-			string filename;
-
-			var xml = _ioService.OpenFileDialog(null, ".xml", "VECTO XML file|*.xml", out filename);
-			if (xml == null) {
-				return;
+			get { return _componentDataValid; }
+			private set {
+				if (_componentDataValid == value) {
+					return;
+				}
+				_componentDataValid = value;
+				RaisePropertyChanged("ComponentDataValid");
 			}
-
-			_busy = true;
-			ComponentDataValid = null;
-			XMLValidationErrors.Clear();
-			DigestValue = "";
-			Source = filename;
-			_stream = xml;
-			DoComputeHash();
 		}
 
+		public ObservableCollection<string> CanonicalizaitionMethods { get; private set; }
+
 		private async void DoComputeHash()
 		{
 			try {
-				var h = VectoHash.Load(_stream);
+				_busy = true;
+				ComponentDataValid = false;
+				DigestValue = "";
+				XMLValidationErrors.Clear();
+
+				var h = VectoHash.Load(_sourceFile.Document);
 
 				_result = h.AddHash();
 
@@ -167,7 +156,7 @@ namespace HashingTool.ViewModel
 										: e.ValidationEventArgs.Message,
 									e.ValidationEventArgs == null ? 0 : e.ValidationEventArgs.Exception.LineNumber)));
 						});
-					await validator.ValidateXML(ms);
+					await validator.ValidateXML(XmlReader.Create(ms));
 				}
 				if (ComponentDataValid != null && ComponentDataValid.Value) {
 					DigestValue = h.ComputeHash();
diff --git a/HashingTool/ViewModel/UserControl/XMLFile.cs b/HashingTool/ViewModel/UserControl/XMLFile.cs
new file mode 100644
index 0000000000..d8dbc70fc9
--- /dev/null
+++ b/HashingTool/ViewModel/UserControl/XMLFile.cs
@@ -0,0 +1,125 @@
+using System;
+using System.Collections.ObjectModel;
+using System.Windows;
+using System.Windows.Input;
+using System.Xml;
+using System.Xml.Schema;
+using HashingTool.Helper;
+using HashingTool.Util;
+
+namespace HashingTool.ViewModel.UserControl
+{
+	public class XMLFile : ObservableObject
+	{
+		private string _source;
+		private bool? _isValid;
+
+		private bool _busy;
+
+		private readonly IOService _ioService;
+		private readonly bool _validate;
+		private XmlDocument _document;
+
+		public XMLFile(IOService ioservice, bool validate = false)
+		{
+			_ioService = ioservice;
+			_validate = validate;
+			XMLValidationErrors = new ObservableCollection<string>();
+			Source = "";
+			RaisePropertyChanged("ValidateInput");
+		}
+
+		public XmlDocument Document
+		{
+			get { return _document; }
+			private set {
+				if (_document == value) {
+					return;
+				}
+				_document = value;
+				RaisePropertyChanged("Document");
+			}
+		}
+
+		public string Source
+		{
+			get { return _source; }
+			private set {
+				if (_source == value) {
+					return;
+				}
+				_source = value;
+				RaisePropertyChanged("Source");
+			}
+		}
+
+		public bool ValidateInput
+		{
+			get { return _validate; }
+		}
+
+		public bool? IsValid
+		{
+			get { return _isValid; }
+			private set {
+				if (_isValid == value) {
+					return;
+				}
+				_isValid = value;
+				RaisePropertyChanged("IsValid");
+			}
+		}
+
+		public ObservableCollection<string> XMLValidationErrors { get; set; }
+
+		public ICommand BrowseFileCommand
+		{
+			get { return new RelayCommand(ReadXMLFile, () => !_busy); }
+		}
+
+
+		private void ReadXMLFile()
+		{
+			string filename;
+
+			var stream = _ioService.OpenFileDialog(null, ".xml", "VECTO XML file|*.xml", out filename);
+			if (stream == null) {
+				return;
+			}
+
+			_busy = true;
+			IsValid = null;
+			XMLValidationErrors.Clear();
+			Source = filename;
+			var reader = XmlReader.Create(stream);
+			var document = new XmlDocument();
+			document.Load(reader);
+			if (_validate) {
+				Validate(reader);
+			}
+			Document = document;
+			_busy = false;
+		}
+
+		private async void Validate(XmlReader xml)
+		{
+			try {
+				IsValid = true;
+				var validator = new XMLValidator(r => { IsValid = r; },
+					(s, e) => {
+						Application.Current.Dispatcher.Invoke(() => XMLValidationErrors.Add(
+							string.Format("Validation {0} Line {2}: {1}", s == XmlSeverityType.Warning ? "WARNING" : "ERROR",
+								e.ValidationEventArgs == null
+									? e.Exception.Message +
+									(e.Exception.InnerException != null ? Environment.NewLine + e.Exception.InnerException.Message : "")
+									: e.ValidationEventArgs.Message,
+								e.ValidationEventArgs == null ? 0 : e.ValidationEventArgs.Exception.LineNumber)));
+					});
+				await validator.ValidateXML(xml);
+			} catch (Exception e) {
+				IsValid = false;
+				XMLValidationErrors.Add(e.Message);
+			}
+		}
+	}
+}
diff --git a/HashingTool/Views/HashComponentData.xaml b/HashingTool/Views/HashComponentData.xaml
index 52cfc9a696..589cdfe43f 100644
--- a/HashingTool/Views/HashComponentData.xaml
+++ b/HashingTool/Views/HashComponentData.xaml
@@ -4,30 +4,94 @@
 	xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 	xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
 	xmlns:ViewModel="clr-namespace:HashingTool.ViewModel" xmlns:Helper="clr-namespace:HashingTool.Helper"
+	xmlns:local="clr-namespace:HashingTool.Views"
 	x:Class="HashingTool.Views.HashComponentData"
 	mc:Ignorable="d"
-	d:DesignHeight="501.425" d:DesignWidth="548">
+	d:DesignHeight="603.125" d:DesignWidth="666">
 	<UserControl.Resources>
-		<Helper:BoolViewConverter x:Key="BoolViewConverter" />
+		<Helper:CollectionConverter x:Key="CollectionConverter" />
 	</UserControl.Resources>
+
 	<UserControl.DataContext>
 		<ViewModel:HashComponentDataViewModel />
 	</UserControl.DataContext>
 	<Grid>
-		<Label HorizontalAlignment="Center" Margin="10,10,0,0" VerticalAlignment="Top"
+		<Label Name="lblHeader" HorizontalAlignment="Center" Margin="10,10,0,0" VerticalAlignment="Top"
 				Content="{Binding Name}" FontWeight="Bold" FontSize="18" />
-		<Button Content="Back" Command="{Binding ShowHomeViewCommand}" Margin="0,0,10,10" HorizontalAlignment="Right"
+		<Button Name="btnBack" Content="Back" Command="{Binding ShowHomeViewCommand}" Margin="0,0,10,10"
+				HorizontalAlignment="Right"
 				Width="75" Height="22" VerticalAlignment="Bottom" />
-		<Button x:Name="btSelectComponentFile" Content="Browse ..." HorizontalAlignment="Left" Margin="300,79,0,0"
-				VerticalAlignment="Top" Width="75" Command="{Binding SetComponentData, Mode=OneWay}" />
-		<TextBox x:Name="tbComponentFile" HorizontalAlignment="Left" Height="23" Margin="10,79,0,0" TextWrapping="Wrap"
-				VerticalAlignment="Top" Width="285" IsReadOnly="True" Text="{Binding Source, Mode=OneWay}" />
-		<Label Content="{Binding ComponentDataValid, Converter={StaticResource BoolViewConverter}, Mode=OneWay}"
-				HorizontalAlignment="Left" Margin="10,141,0,0" VerticalAlignment="Top" Height="26" Width="154" />
-		<Label Content="{Binding DigestValue}" HorizontalAlignment="Left" Margin="10,172,0,0" VerticalAlignment="Top" />
-		<Button Content="Save" HorizontalAlignment="Right" Margin="0,0,90,10" Width="75" Height="22"
+		<Button Content="Save Component Data" HorizontalAlignment="Right" Margin="0,0,90,10" Width="143" Height="22"
 				VerticalAlignment="Bottom" Command="{Binding SaveHashedDocument, Mode=OneWay}" />
-		<ListBox HorizontalAlignment="Left" Height="214" Margin="71,230,0,0" VerticalAlignment="Top" Width="436" IsSynchronizedWithCurrentItem="False" ItemsSource="{Binding XMLValidationErrors}"/>
+
+		<local:VectoXMLFileSelector Margin="0,93,0,0" VerticalAlignment="Top" XMLFile="{Binding ComponentFile}" />
+
+		<Grid Height="425" VerticalAlignment="Top" Margin="15,141,5,0">
+			<Grid.RowDefinitions>
+				<RowDefinition Height="Auto" />
+				<RowDefinition Height="Auto" />
+				<RowDefinition Height="Auto" />
+			</Grid.RowDefinitions>
+			<Expander Grid.Row="0">
+				<Expander.Style>
+					<Style TargetType="Expander">
+						<Setter Property="IsEnabled" Value="True" />
+						<Setter Property="Foreground" Value="Red" />
+						<Style.Triggers>
+							<DataTrigger Binding="{Binding XMLValidationErrors.Count}" Value="0">
+								<Setter Property="IsExpanded" Value="False" />
+								<Setter Property="IsEnabled" Value="False" />
+								<Setter Property="Foreground" Value="Black" />
+							</DataTrigger>
+						</Style.Triggers>
+					</Style>
+				</Expander.Style>
+				<Expander.Header>
+					<TextBlock Text="{Binding XMLValidationErrors.Count, StringFormat='{}{0} Warnings/Errors'}" />
+				</Expander.Header>
+
+				<Grid Background="#FFE5E5E5" Margin="10,0,8,0">
+					<ListBox Height="185" VerticalAlignment="Top" IsSynchronizedWithCurrentItem="False"
+							ItemsSource="{Binding XMLValidationErrors}" />
+				</Grid>
+
+			</Expander>
+			<Grid Grid.Row="1" Margin="0,10,0,0">
+				<Label x:Name="lblDigestValue" Content="Digest Value:" HorizontalAlignment="Left" Margin="10,38,0,0"
+						VerticalAlignment="Top" RenderTransformOrigin="0.57,0.5" FontSize="16" />
+				<TextBox x:Name="tbDigestValue" Text="{Binding DigestValue}" HorizontalAlignment="Left" Margin="117,41,0,0"
+						VerticalAlignment="Top" RenderTransformOrigin="4.1,-2.1" Width="454" FontFamily="Courier New" FontWeight="Bold"
+						FontSize="16" Foreground="#FF03932B" />
+				<Label Name="lblC14N" Content="Canonicalization:" HorizontalAlignment="Left" Margin="10,10,0,0"
+						VerticalAlignment="Top" />
+				<Label Name="lblC14NList"
+						Content="{Binding CanonicalizaitionMethods, Converter={StaticResource CollectionConverter}}"
+						HorizontalAlignment="Left" Margin="117,10,0,0" VerticalAlignment="Top"
+						Width="454" />
+			</Grid>
+			<Grid Grid.Row="2" Margin="0,10,0,0">
+				<ContentControl HorizontalAlignment="Center" Margin="0,0,0,0" VerticalAlignment="Top" Width="66" Height="64">
+					<ContentControl.RenderTransform>
+						<ScaleTransform ScaleX="1.5" ScaleY="1.5" />
+					</ContentControl.RenderTransform>
+					<ContentControl.Style>
+						<Style TargetType="ContentControl">
+							<Setter Property="Content" Value="" />
+							<Style.Triggers>
+								<DataTrigger Binding="{Binding ComponentDataValid}" Value="True">
+									<Setter Property="Content" Value="{StaticResource Icon_OK}" />
+								</DataTrigger>
+								<DataTrigger Binding="{Binding ComponentDataValid}" Value="False">
+									<Setter Property="Content" Value="{StaticResource Icon_NOK}" />
+								</DataTrigger>
+							</Style.Triggers>
+						</Style>
+					</ContentControl.Style>
+				</ContentControl>
+
+			</Grid>
+		</Grid>
+		<Label x:Name="lblFileSelect" Content="Component data:" HorizontalAlignment="Left" Margin="10,75,0,0" VerticalAlignment="Top"/>
 
 	</Grid>
 </UserControl>
\ No newline at end of file
diff --git a/HashingTool/Views/UserControl/VectoXMLFileSelector.xaml b/HashingTool/Views/UserControl/VectoXMLFileSelector.xaml
new file mode 100644
index 0000000000..e216cb6acf
--- /dev/null
+++ b/HashingTool/Views/UserControl/VectoXMLFileSelector.xaml
@@ -0,0 +1,37 @@
+<UserControl
+	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+	xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+	xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+	xmlns:views="clr-namespace:HashingTool.Views"
+	x:Class="HashingTool.Views.VectoXMLFileSelector"
+	mc:Ignorable="d" d:DesignWidth="456" MinHeight="43"
+	d:DataContext="{d:DesignInstance views:VectoXMLFileSelector}" Height="34">
+	<UserControl.Resources>
+		<BooleanToVisibilityConverter x:Key="BoolToVis" />
+	</UserControl.Resources>
+	<Grid>
+		<TextBox Height="23" Margin="10,10,140,0" TextWrapping="Wrap" Text="{Binding XMLFile.Source}" VerticalAlignment="Top" />
+		<Button Content="Browse ..." Command="{Binding XMLFile.BrowseFileCommand, Mode=OneWay}" Margin="0,10,10,0"
+				VerticalAlignment="Top" HorizontalAlignment="Right" Width="75" />
+		<ContentControl Visibility="{Binding XMLFile.ValidateInput, Converter={StaticResource BoolToVis}}" Height="33"
+						Margin="0,14,40,-4" VerticalAlignment="Top" HorizontalAlignment="Right" Width="93">
+			<ContentControl.RenderTransform>
+				<ScaleTransform ScaleX="0.5" ScaleY="0.5" />
+			</ContentControl.RenderTransform>
+			<ContentControl.Style>
+				<Style TargetType="ContentControl">
+					<Setter Property="Content" Value="{StaticResource ICON_XML_unknown}" />
+					<Style.Triggers>
+						<DataTrigger Binding="{Binding XMLFile.IsValid}" Value="True">
+							<Setter Property="Content" Value="{StaticResource Icon_XML_OK}" />
+						</DataTrigger>
+						<DataTrigger Binding="{Binding XMLFile.IsValid}" Value="False">
+							<Setter Property="Content" Value="{StaticResource Icon_XML_NOK}" />
+						</DataTrigger>
+					</Style.Triggers>
+				</Style>
+			</ContentControl.Style>
+		</ContentControl>
+	</Grid>
+</UserControl>
\ No newline at end of file
diff --git a/HashingTool/Views/UserControl/VectoXMLFileSelector.xaml.cs b/HashingTool/Views/UserControl/VectoXMLFileSelector.xaml.cs
new file mode 100644
index 0000000000..887cb6c676
--- /dev/null
+++ b/HashingTool/Views/UserControl/VectoXMLFileSelector.xaml.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using HashingTool.ViewModel;
+using HashingTool.ViewModel.UserControl;
+
+namespace HashingTool.Views
+{
+	/// <summary>
+	/// Interaction logic for VectoXMLFileSelector.xaml
+	/// </summary>	
+	public partial class VectoXMLFileSelector : UserControl
+	{
+		public static readonly DependencyProperty XMLFileProperty = DependencyProperty.Register("XMLFile", typeof(XMLFile),
+			typeof(VectoXMLFileSelector));
+
+
+		public VectoXMLFileSelector()
+		{
+			InitializeComponent();
+			(Content as FrameworkElement).DataContext = this;
+		}
+
+		public XMLFile XMLFile
+		{
+			get { return (XMLFile)GetValue(XMLFileProperty); }
+			set { SetValue(XMLFileProperty, value); }
+		}
+	}
+}
diff --git a/VectoCommon/VectoHashing/Impl/XmlDsigVectoTransform.cs b/VectoCommon/VectoHashing/Impl/XmlDsigVectoTransform.cs
index 685ec972e0..e2b8f300d1 100644
--- a/VectoCommon/VectoHashing/Impl/XmlDsigVectoTransform.cs
+++ b/VectoCommon/VectoHashing/Impl/XmlDsigVectoTransform.cs
@@ -29,74 +29,74 @@
 *   Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology
 */
 
-using System;
-using System.IO;
-using System.Reflection;
-using System.Security.Cryptography.Xml;
-using System.Text;
-using System.Xml;
-
-namespace TUGraz.VectoHashing
-{
-	public class XmlDsigVectoTransform : Transform
-	{
-		//private static readonly Type[] _inputTypes = { typeof(Stream), typeof(XmlDocument), typeof(XmlNodeList) };
-		//private static readonly Type[] _outputTypes = { typeof(Stream) };
-		//private XmlDocument _doc = new XmlDocument();
-
-		private XmlDsigXsltTransform _transform;
-
-		public XmlDsigVectoTransform()
-		{
-			Algorithm = "urn:vecto:xml:2017:canonicalization";
-			_transform = new XmlDsigXsltTransform();
-
-			XmlDocument doc = new XmlDocument();
-			doc.Load(ReadStream("TUGraz.VectoHashing.Resources.XSLT.SortInputData.xslt"));
-
-			_transform.LoadInnerXml(doc.ChildNodes);
-		}
-
-		public override void LoadInnerXml(XmlNodeList nodeList) {}
-
-		protected override XmlNodeList GetInnerXml()
-		{
-			return null;
-		}
-
-		public override void LoadInput(object obj)
-		{
-			_transform.LoadInput(obj);
-		}
-
-		public override object GetOutput()
-		{
-			return _transform.GetOutput();
-		}
-
-		public override object GetOutput(Type type)
-		{
-			return _transform.GetOutput(type);
-		}
-
-		public override Type[] InputTypes
-		{
-			get { return _transform.InputTypes; }
-		}
-
-		public override Type[] OutputTypes
-		{
-			get { return _transform.OutputTypes; }
-		}
-
-		private static Stream ReadStream(string resourceName)
-		{
-			var assembly = Assembly.GetExecutingAssembly();
-			var resource = assembly.GetManifestResourceStream(resourceName);
-			if (resource == null) {
-				throw new Exception("Resource file not found: " + resourceName);
-			}
-			return resource;
-		}
-	}
-}
\ No newline at end of file
+using System;
+using System.IO;
+using System.Reflection;
+using System.Security.Cryptography.Xml;
+using System.Text;
+using System.Xml;
+
+namespace TUGraz.VectoHashing
+{
+	public class XmlDsigVectoTransform : Transform
+	{
+		//private static readonly Type[] _inputTypes = { typeof(Stream), typeof(XmlDocument), typeof(XmlNodeList) };
+		//private static readonly Type[] _outputTypes = { typeof(Stream) };
+		//private XmlDocument _doc = new XmlDocument();
+
+		private XmlDsigXsltTransform _transform;
+
+		public XmlDsigVectoTransform()
+		{
+			Algorithm = "urn:vecto:xml:2017:canonicalization";
+			_transform = new XmlDsigXsltTransform();
+
+			XmlDocument doc = new XmlDocument();
+			doc.Load(ReadStream("TUGraz.VectoHashing.Resources.XSLT.SortInputData.xslt"));
+
+			_transform.LoadInnerXml(doc.ChildNodes);
+		}
+
+		public override void LoadInnerXml(XmlNodeList nodeList) {}
+
+		protected override XmlNodeList GetInnerXml()
+		{
+			return null;
+		}
+
+		public override void LoadInput(object obj)
+		{
+			_transform.LoadInput(obj);
+		}
+
+		public override object GetOutput()
+		{
+			return _transform.GetOutput();
+		}
+
+		public override object GetOutput(Type type)
+		{
+			return _transform.GetOutput(type);
+		}
+
+		public override Type[] InputTypes
+		{
+			get { return _transform.InputTypes; }
+		}
+
+		public override Type[] OutputTypes
+		{
+			get { return _transform.OutputTypes; }
+		}
+
+		private static Stream ReadStream(string resourceName)
+		{
+			var assembly = Assembly.GetExecutingAssembly();
+			var resource = assembly.GetManifestResourceStream(resourceName);
+			if (resource == null) {
+				throw new Exception("Resource file not found: " + resourceName);
+			}
+			return resource;
+		}
+	}
+}
-- 
GitLab