Merge pull request #2964 from ludovic-henry/sgen-monocontext
[mono.git] / mcs / class / referencesource / System.Web / Util / HashCodeCombiner.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="HashCodeCombiner.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>                                                                
5 //------------------------------------------------------------------------------
6
7 /*
8  * HashCodeCombiner class
9  * 
10  * Copyright (c) 1999 Microsoft Corporation
11  */
12
13 namespace System.Web.Util {
14 using System.Text;
15 using System.IO;
16 using System.Globalization;
17 using System.Diagnostics;
18 using System.Diagnostics.CodeAnalysis;
19 using System.Web.Security.Cryptography;
20
21 /*
22  * Class used to combine several hashcodes into a single hashcode
23  */
24 internal class HashCodeCombiner {
25
26     private long _combinedHash;
27
28     internal HashCodeCombiner() {
29        // Start with a seed (obtained from String.GetHashCode implementation)
30        _combinedHash = 5381;
31     }
32
33     internal HashCodeCombiner(long initialCombinedHash)   {
34         _combinedHash = initialCombinedHash;
35     }
36
37     internal static int CombineHashCodes(int h1, int h2) {
38         return ((h1 << 5) + h1) ^ h2;
39     }
40
41     internal static int CombineHashCodes(int h1, int h2, int h3) {
42         return CombineHashCodes(CombineHashCodes(h1, h2), h3);
43     }
44
45     internal static int CombineHashCodes(int h1, int h2, int h3, int h4) {
46         return CombineHashCodes(CombineHashCodes(h1, h2), CombineHashCodes(h3, h4));
47     }
48
49     internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5) {
50         return CombineHashCodes(CombineHashCodes(h1, h2, h3, h4), h5);
51     }
52
53     internal static string GetDirectoryHash(VirtualPath virtualDir) {
54         HashCodeCombiner hashCodeCombiner = new HashCodeCombiner();
55         hashCodeCombiner.AddDirectory(virtualDir.MapPathInternal());
56         return hashCodeCombiner.CombinedHashString;
57     }
58
59     internal void AddArray(string[] a) {
60         if (a != null) {
61             int n = a.Length;
62             for (int i = 0; i < n; i++) {
63                 AddObject(a[i]);
64             }
65         }
66     }
67
68     internal void AddInt(int n) {
69         _combinedHash = ((_combinedHash << 5) + _combinedHash) ^ n;
70         Debug.Trace("HashCodeCombiner", "Adding " + n.ToString("x") + " --> " + _combinedHash.ToString("x"));
71     }
72
73     internal void AddObject(int n) {
74         AddInt(n);
75     }
76
77     internal void AddObject(byte b) {
78         AddInt(b.GetHashCode());
79     }
80
81     internal void AddObject(long l) {
82         AddInt(l.GetHashCode());
83     }
84
85     internal void AddObject(bool b) {
86         AddInt(b.GetHashCode());
87     }
88
89     internal void AddObject(string s) {
90         if (s != null)
91             AddInt(StringUtil.GetStringHashCode(s));
92     }
93
94     internal void AddObject(Type t) {
95         if (t != null)
96             AddObject(System.Web.UI.Util.GetAssemblyQualifiedTypeName(t));
97     }
98
99     internal void AddObject(object o) {
100         if (o != null)
101             AddInt(o.GetHashCode());
102     }
103
104     internal void AddCaseInsensitiveString(string s) {
105         if (s != null)
106             AddInt(StringUtil.GetNonRandomizedHashCode(s, ignoreCase:true));
107     }
108
109     internal void AddDateTime(DateTime dt) {
110         Debug.Trace("HashCodeCombiner", "Ticks: " + dt.Ticks.ToString("x", CultureInfo.InvariantCulture));
111         Debug.Trace("HashCodeCombiner", "Hashcode: " + dt.GetHashCode().ToString("x", CultureInfo.InvariantCulture));
112         AddInt(dt.GetHashCode());
113     }
114
115     private void AddFileSize(long fileSize) {
116         Debug.Trace("HashCodeCombiner", "file size: " + fileSize.ToString("x", CultureInfo.InvariantCulture));
117         Debug.Trace("HashCodeCombiner", "Hashcode: " + fileSize.GetHashCode().ToString("x", CultureInfo.InvariantCulture));
118         AddInt(fileSize.GetHashCode());
119     }
120
121     [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "This call site is trusted.")]
122     private void AddFileVersionInfo(FileVersionInfo fileVersionInfo) {
123         Debug.Trace("HashCodeCombiner", "FileMajorPart: " + fileVersionInfo.FileMajorPart.GetHashCode().ToString("x", CultureInfo.InvariantCulture));
124         Debug.Trace("HashCodeCombiner", "FileMinorPart: " + fileVersionInfo.FileMinorPart.GetHashCode().ToString("x", CultureInfo.InvariantCulture));
125         Debug.Trace("HashCodeCombiner", "FileBuildPart: " + fileVersionInfo.FileBuildPart.GetHashCode().ToString("x", CultureInfo.InvariantCulture));
126         Debug.Trace("HashCodeCombiner", "FilePrivatePart: " + fileVersionInfo.FilePrivatePart.GetHashCode().ToString("x", CultureInfo.InvariantCulture));
127         AddInt(fileVersionInfo.FileMajorPart.GetHashCode());
128         AddInt(fileVersionInfo.FileMinorPart.GetHashCode());
129         AddInt(fileVersionInfo.FileBuildPart.GetHashCode());
130         AddInt(fileVersionInfo.FilePrivatePart.GetHashCode());
131     }
132
133     private void AddFileContentHashKey(string fileContentHashKey) {
134         AddInt(StringUtil.GetNonRandomizedHashCode(fileContentHashKey));
135     }
136
137     internal void AddFileContentHash(string fileName) {
138         // Convert file content to hash bytes
139         byte[] fileContentBytes = File.ReadAllBytes(fileName);
140         byte[] fileContentHashBytes = CryptoUtil.ComputeSHA256Hash(fileContentBytes);
141
142         // Convert byte[] to hex string representation
143         StringBuilder sbFileContentHashBytes = new StringBuilder();
144         for (int index = 0; index < fileContentHashBytes.Length; index++) {
145             sbFileContentHashBytes.Append(fileContentHashBytes[index].ToString("X2", CultureInfo.InvariantCulture));
146         }
147
148         AddFileContentHashKey(sbFileContentHashBytes.ToString());
149     }
150
151     internal void AddFile(string fileName) {
152         Debug.Trace("HashCodeCombiner", "AddFile: " + fileName);
153         if (!FileUtil.FileExists(fileName)) {
154
155             // Review: Should we change the dependency model to take directory into account?
156             if (FileUtil.DirectoryExists(fileName)) {
157                 // Add as a directory dependency if it's a directory.
158                 AddDirectory(fileName);
159                 return;
160             }
161
162             Debug.Trace("HashCodeCombiner", "Could not find target " + fileName);
163             return;
164         }
165
166         AddExistingFile(fileName);
167     }
168
169     // Same as AddFile, but only called for a file which is known to exist
170     private void AddExistingFile(string fileName) {
171         Debug.Trace("HashCodeCombiner", "AddExistingFile: " + fileName);
172
173         AddInt(StringUtil.GetStringHashCode(fileName));
174         FileInfo file = new FileInfo(fileName);
175         if (!AppSettings.PortableCompilationOutput) {
176             AddDateTime(file.CreationTimeUtc);
177         }
178         AddDateTime(file.LastWriteTimeUtc);
179         AddFileSize(file.Length);
180     }
181
182     [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "This call site is trusted.")]
183     internal void AddExistingFileVersion(string fileName) {
184         Debug.Trace("HashCodeCombiner", "AddExistingFileVersion: " + fileName);
185
186         AddInt(StringUtil.GetStringHashCode(fileName));
187         FileVersionInfo fileVersionInfo = FileVersionInfo.GetVersionInfo(fileName);
188
189         AddFileVersionInfo(fileVersionInfo);
190     }
191
192     internal void AddDirectory(string directoryName) {
193
194         DirectoryInfo directory = new DirectoryInfo(directoryName);
195         if (!directory.Exists) {
196             return;
197         }
198
199         AddObject(directoryName);
200
201         // Go through all the files in the directory
202         foreach (FileData fileData in FileEnumerator.Create(directoryName)) {
203
204             if (fileData.IsDirectory)
205                 AddDirectory(fileData.FullName);
206             else
207                 AddExistingFile(fileData.FullName);
208         }
209
210         if (!AppSettings.PortableCompilationOutput) {
211             AddDateTime(directory.CreationTimeUtc);
212             AddDateTime(directory.LastWriteTimeUtc);
213         }
214     }
215
216     // Same as AddDirectory, but only look at files that don't have a culture
217     internal void AddResourcesDirectory(string directoryName) {
218
219         DirectoryInfo directory = new DirectoryInfo(directoryName);
220         if (!directory.Exists) {
221             return;
222         }
223
224         AddObject(directoryName);
225
226         // Go through all the files in the directory
227         foreach (FileData fileData in FileEnumerator.Create(directoryName)) {
228
229             if (fileData.IsDirectory)
230                 AddResourcesDirectory(fileData.FullName);
231             else {
232                 // Ignore the file if it has a culture, since only neutral files
233                 // need to re-trigger compilation (VSWhidbey 359029)
234                 string fullPath = fileData.FullName;
235                 if (System.Web.UI.Util.GetCultureName(fullPath) == null) {
236                     AddExistingFile(fullPath);
237                 }
238             }
239         }
240
241         if (!AppSettings.PortableCompilationOutput) {
242             AddDateTime(directory.CreationTimeUtc);
243         }
244     }
245
246     internal long CombinedHash { get { return _combinedHash; } }
247     internal int CombinedHash32 { get { return _combinedHash.GetHashCode(); } }
248
249     internal string CombinedHashString {
250         get {
251             return _combinedHash.ToString("x", CultureInfo.InvariantCulture);
252         }
253     }
254 }
255
256
257 }