Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- namespace XmlSignatureTests
- {
- using System.Xml;
- public class XmlHash
- {
- private class HashAlgorithm
- {
- public ulong Hash;
- internal static ulong GetHash(string data)
- {
- return GetHash(data, 0);
- }
- internal void AddString(string data)
- {
- Hash = GetHash(data, Hash);
- }
- internal void AddInt(int i)
- {
- Hash += (Hash << 11 ) + (ulong)i;
- }
- internal void AddULong(ulong u)
- {
- Hash += (Hash << 11 ) + u;
- }
- private static ulong GetHash( string data, ulong hash )
- {
- hash += ( hash << 13 ) + (ulong)data.Length;
- // ReSharper disable once ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator
- foreach (var t in data)
- {
- hash += ( hash << 17 ) + t;
- }
- return hash;
- }
- }
- private const string Delimiter = "\0x01";
- public bool IgnoreChildOrder;
- public bool IgnoreComments;
- public bool IgnoreDtd;
- public bool IgnoreNamespaces;
- public bool IgnorePi;
- public bool IgnorePrefixes;
- public bool IgnoreWhitespace;
- public bool IgnoreXmlDecl;
- internal ulong ComputeHash(XmlNode node)
- {
- if (node.NodeType == XmlNodeType.Document ||
- node.NodeType == XmlNodeType.DocumentFragment)
- {
- return ComputeHashXmlFragment(node);
- }
- return ComputeHashXmlNode(node);
- }
- private ulong ComputeHashXmlFragment(XmlNode frag)
- {
- var ha = new HashAlgorithm();
- ComputeHashXmlChildren(ha, frag);
- return ha.Hash;
- }
- private void ComputeHashXmlChildren(HashAlgorithm ha, XmlNode parent)
- {
- if (parent is XmlElement el)
- {
- ulong attrHashSum = 0;
- var attrsCount = 0;
- var attrs = el.Attributes;
- for (var i = 0; i < attrs.Count; i++)
- {
- var attr = (XmlAttribute) attrs.Item(i);
- ulong hashValue;
- if (attr.LocalName == "xmlns" && attr.Prefix == string.Empty)
- {
- if (IgnoreNamespaces) continue;
- hashValue = HashNamespace(string.Empty, attr.Value);
- }
- else if (attr.Prefix == "xmlns")
- {
- if (IgnoreNamespaces) continue;
- hashValue = HashNamespace(attr.LocalName, attr.Value);
- }
- else
- {
- hashValue = HashAttribute(attr.LocalName,
- attr.Prefix,
- attr.NamespaceURI,
- IgnoreWhitespace
- ? NormalizeText(attr.Value)
- : attr.Value);
- }
- attrsCount++;
- attrHashSum += hashValue;
- }
- if (attrsCount != 0)
- {
- ha.AddULong(attrHashSum);
- ha.AddInt(attrsCount);
- }
- }
- var childrenCount = 0;
- if (IgnoreChildOrder)
- {
- ulong totalHashSum = 0;
- var curChild = parent.FirstChild;
- while (curChild != null)
- {
- var hashValue = ComputeHashXmlNode(curChild);
- if (hashValue != 0)
- {
- totalHashSum += hashValue;
- childrenCount++;
- }
- curChild = curChild.NextSibling;
- }
- ha.AddULong(totalHashSum);
- }
- else
- {
- var curChild = parent.FirstChild;
- while (curChild != null)
- {
- var hashValue = ComputeHashXmlNode(curChild);
- if (hashValue != 0)
- {
- ha.AddULong(hashValue);
- childrenCount++;
- }
- curChild = curChild.NextSibling;
- }
- }
- if (childrenCount != 0)
- ha.AddInt(childrenCount);
- }
- private ulong ComputeHashXmlNode(XmlNode node)
- {
- switch (node.NodeType)
- {
- case XmlNodeType.Element:
- {
- var el = (XmlElement) node;
- var ha = new HashAlgorithm();
- HashElement(ha, el.LocalName, el.Prefix, el.NamespaceURI);
- ComputeHashXmlChildren(ha, el);
- return ha.Hash;
- }
- case XmlNodeType.Attribute:
- return 0;
- case XmlNodeType.Whitespace:
- return 0;
- case XmlNodeType.SignificantWhitespace:
- if (!IgnoreWhitespace)
- goto case XmlNodeType.Text;
- return 0;
- case XmlNodeType.Comment:
- if (!IgnoreComments)
- return HashCharacterNode(XmlNodeType.Comment, ((XmlCharacterData) node).Value);
- return 0;
- case XmlNodeType.Text:
- {
- var cd = (XmlCharacterData) node;
- if (IgnoreWhitespace)
- return HashCharacterNode(cd.NodeType, NormalizeText(cd.Value));
- return HashCharacterNode(cd.NodeType, cd.Value);
- }
- case XmlNodeType.CDATA:
- {
- var cd = (XmlCharacterData) node;
- return HashCharacterNode(cd.NodeType, cd.Value);
- }
- case XmlNodeType.ProcessingInstruction:
- {
- if (IgnorePi)
- return 0;
- var pi = (XmlProcessingInstruction) node;
- return HashPi(pi.Target, pi.Value);
- }
- case XmlNodeType.EntityReference:
- {
- var er = (XmlEntityReference) node;
- return HashEr(er.Name);
- }
- case XmlNodeType.XmlDeclaration:
- {
- if (IgnoreXmlDecl)
- return 0;
- var decl = (XmlDeclaration) node;
- return HashXmlDeclaration(NormalizeXmlDeclaration(decl.Value));
- }
- case XmlNodeType.DocumentType:
- {
- if (IgnoreDtd)
- return 0;
- var docType = (XmlDocumentType) node;
- return HashDocumentType(docType.Name, docType.PublicId, docType.SystemId, docType.InternalSubset);
- }
- case XmlNodeType.DocumentFragment:
- return 0;
- default:
- return 0;
- }
- }
- private void HashElement(HashAlgorithm ha, string localName, string prefix, string ns)
- {
- ha.AddString((int) XmlNodeType.Element +
- Delimiter +
- (IgnoreNamespaces || IgnorePrefixes ? string.Empty : prefix) +
- Delimiter +
- (IgnoreNamespaces ? string.Empty : ns) +
- Delimiter +
- localName);
- }
- private ulong HashAttribute(string localName, string prefix, string ns, string value)
- {
- return HashAlgorithm.GetHash((int) XmlNodeType.Attribute +
- Delimiter +
- (IgnoreNamespaces || IgnorePrefixes ? string.Empty : prefix) +
- Delimiter +
- (IgnoreNamespaces ? string.Empty : ns) +
- Delimiter +
- localName +
- Delimiter +
- value);
- }
- private ulong HashNamespace(string prefix, string ns)
- {
- return HashAlgorithm.GetHash(100 +
- Delimiter +
- (IgnorePrefixes ? string.Empty : prefix) +
- Delimiter +
- ns);
- }
- private static ulong HashCharacterNode(XmlNodeType nodeType, string value)
- {
- return HashAlgorithm.GetHash((int) nodeType +
- Delimiter +
- value);
- }
- private static ulong HashPi(string target, string value)
- {
- return HashAlgorithm.GetHash((int) XmlNodeType.ProcessingInstruction +
- Delimiter +
- target +
- Delimiter +
- value);
- }
- private static ulong HashEr(string name)
- {
- return HashAlgorithm.GetHash((int) XmlNodeType.EntityReference +
- Delimiter +
- name);
- }
- private static ulong HashXmlDeclaration(string value)
- {
- return HashAlgorithm.GetHash((int) XmlNodeType.XmlDeclaration +
- Delimiter +
- value);
- }
- private static ulong HashDocumentType(string name, string publicId, string systemId, string subset)
- {
- return HashAlgorithm.GetHash((int) XmlNodeType.DocumentType +
- Delimiter +
- name +
- Delimiter +
- publicId +
- Delimiter +
- systemId +
- Delimiter +
- subset);
- }
- private static string NormalizeXmlDeclaration( string value )
- {
- value = value.Replace( '\'', '"' );
- return NormalizeText( value );
- }
- private static string NormalizeText( string text )
- {
- var chars = text.ToCharArray();
- var i = 0;
- var j = 0;
- for (;;)
- {
- while (j < chars.Length && char.IsWhiteSpace(text[j]))
- {
- j++;
- }
- while (j < chars.Length && !char.IsWhiteSpace(text[j]))
- {
- chars[i++]=chars[j++];
- }
- if (j < chars.Length)
- {
- chars[i++] = ' ';
- j++;
- }
- else
- {
- if (j == 0 || i == 0)
- {
- return string.Empty;
- }
- if (char.IsWhiteSpace(chars[j - 1]))
- {
- i--;
- }
- return new string(chars, 0, i);
- }
- }
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement