Skip to content

Commit 218f024

Browse files
committed
Go back to simple bytewise comparison
1 parent d67d10b commit 218f024

File tree

1 file changed

+48
-95
lines changed

1 file changed

+48
-95
lines changed

src/tasks/Common/Utils.cs

Lines changed: 48 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -214,90 +214,60 @@ public static (int, string) TryRunProcess(
214214
return (process.ExitCode, outputBuilder.ToString().Trim('\r', '\n'));
215215
}
216216

217-
internal abstract class Readable<TContent, TReader> :
218-
IDisposable
219-
where TContent : IEquatable<TContent>
220-
where TReader : IDisposable
217+
private static bool ContentEqual(string fileA, string fileB)
221218
{
222-
protected abstract int Read(TContent[] buffer, int offset, int count);
223-
protected TReader _reader;
224-
protected Readable(TReader reader) => _reader = reader;
225-
public void Dispose() => _reader.Dispose();
219+
const int bufferSize = 8192;
220+
FileStream streamA = new(fileA, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: bufferSize, FileOptions.SequentialScan);
221+
FileStream streamB = new(fileB, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: bufferSize, FileOptions.SequentialScan);
226222

227-
protected static bool ContentEqual(Readable<TContent, TReader> streamA, Readable<TContent, TReader> streamB, int bufferSize)
228-
{
229-
TContent[] bufferA = new TContent[bufferSize];
230-
TContent[] bufferB = new TContent[bufferSize];
223+
if (streamA.Length != streamB.Length)
224+
return false;
231225

232-
int readA = 0;
233-
int readB = 0;
234-
int consumedA = 0;
235-
int consumedB = 0;
226+
byte[] bufferA = new byte[bufferSize];
227+
byte[] bufferB = new byte[bufferSize];
236228

237-
while (true)
238-
{
239-
if (consumedA == readA)
240-
{
241-
readA = streamA.Read(bufferA, 0, bufferSize);
242-
consumedA = 0;
243-
}
229+
int readA = 0;
230+
int readB = 0;
231+
int consumedA = 0;
232+
int consumedB = 0;
244233

245-
if (consumedB == readB)
246-
{
247-
readB = streamB.Read(bufferB, 0, bufferSize);
248-
consumedB = 0;
249-
}
234+
while (true)
235+
{
236+
if (consumedA == readA)
237+
{
238+
readA = streamA.Read(bufferA, 0, bufferSize);
239+
consumedA = 0;
240+
}
250241

251-
if (readA == 0 && readB == 0)
252-
return true;
242+
if (consumedB == readB)
243+
{
244+
readB = streamB.Read(bufferB, 0, bufferSize);
245+
consumedB = 0;
246+
}
253247

254-
if (readA == 0 || readB == 0)
255-
return false;
248+
if (readA == 0 && readB == 0)
249+
return true;
256250

257-
int overlap = Math.Min(readA - consumedA, readB - consumedB);
258-
if (!bufferA.AsSpan(consumedA, overlap).SequenceEqual(bufferB.AsSpan(consumedB, overlap)))
259-
return false;
251+
if (readA == 0 || readB == 0)
252+
return false;
260253

261-
consumedA += overlap;
262-
consumedB += overlap;
263-
}
264-
}
265-
}
254+
int overlap = Math.Min(readA - consumedA, readB - consumedB);
255+
if (!bufferA.AsSpan(consumedA, overlap).SequenceEqual(bufferB.AsSpan(consumedB, overlap)))
256+
return false;
266257

267-
private sealed class TextFileComparer : Readable<char, StreamReader>
268-
{
269-
private const int _charCount = 8192 / sizeof(char);
270-
private TextFileComparer(string path) : base(new StreamReader(path, Encoding.UTF8, true, _charCount)) { }
271-
protected override int Read(char[] buffer, int offset, int count) => _reader.Read(buffer, offset, count);
272-
public static bool ContentEqual(string filePath1, string filePath2)
273-
{
274-
using var streamA = new TextFileComparer(filePath1);
275-
using var streamB = new TextFileComparer(filePath2);
276-
return ContentEqual(streamA, streamB, bufferSize: _charCount);
277-
}
278-
}
279-
280-
private sealed class BinaryFileComparer : Readable<byte, FileStream>
281-
{
282-
private const int _byteCount = 8192;
283-
private BinaryFileComparer(string path) : base (new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read,
284-
bufferSize: _byteCount, FileOptions.SequentialScan)) {}
285-
protected override int Read(byte[] buffer, int offset, int count) => _reader.Read(buffer, offset, count);
286-
public static bool ContentEqual(string filePath1, string filePath2)
287-
{
288-
using var streamA = new BinaryFileComparer(filePath1);
289-
using var streamB = new BinaryFileComparer(filePath2);
290-
return ContentEqual(streamA, streamB, bufferSize: _byteCount);
258+
consumedA += overlap;
259+
consumedB += overlap;
291260
}
292261
}
293262

263+
#pragma warning disable IDE0060 // Remove unused parameter
294264
public static bool CopyIfDifferent(string src, string dst, bool useHash)
265+
#pragma warning restore IDE0060 // Remove unused parameter
295266
{
296267
if (!File.Exists(src))
297268
throw new ArgumentException($"Cannot find {src} file to copy", nameof(src));
298269

299-
bool areDifferent = !File.Exists(dst) || (useHash && !BinaryFileComparer.ContentEqual(src, dst)) || (!useHash && !TextFileComparer.ContentEqual(src, dst));
300-
270+
bool areDifferent = !File.Exists(dst) || !ContentEqual(src, dst);
301271
if (areDifferent)
302272
File.Copy(src, dst, true);
303273

@@ -327,41 +297,24 @@ private static string ToBase64SafeString(byte[] data)
327297

328298
private static byte[] ComputeHashFromStream(Stream stream, HashAlgorithmType algorithm)
329299
{
330-
if (algorithm == HashAlgorithmType.SHA512)
331-
{
332-
using HashAlgorithm hashAlgorithm = SHA512.Create();
333-
return hashAlgorithm.ComputeHash(stream);
334-
}
335-
else if (algorithm == HashAlgorithmType.SHA384)
336-
{
337-
using HashAlgorithm hashAlgorithm = SHA384.Create();
338-
return hashAlgorithm.ComputeHash(stream);
339-
}
340-
else if (algorithm == HashAlgorithmType.SHA256)
341-
{
342-
using HashAlgorithm hashAlgorithm = SHA256.Create();
343-
return hashAlgorithm.ComputeHash(stream);
344-
}
345-
else
300+
using HashAlgorithm hash = algorithm switch
346301
{
347-
throw new ArgumentException($"Unsupported hash algorithm: {algorithm}");
348-
}
302+
HashAlgorithmType.SHA512 => SHA512.Create(),
303+
HashAlgorithmType.SHA384 => SHA384.Create(),
304+
HashAlgorithmType.SHA256 => SHA256.Create(),
305+
_ => throw new ArgumentException($"Unsupported hash algorithm: {algorithm}")
306+
};
307+
return hash.ComputeHash(stream);
349308
}
350309

351310
private static string EncodeHash(byte[] data, HashEncodingType encoding)
352311
{
353-
if (encoding == HashEncodingType.Base64)
354-
{
355-
return Convert.ToBase64String(data);
356-
}
357-
else if (encoding == HashEncodingType.Base64Safe)
312+
return encoding switch
358313
{
359-
return ToBase64SafeString(data);
360-
}
361-
else
362-
{
363-
throw new ArgumentException($"Unsupported hash encoding: {encoding}");
364-
}
314+
HashEncodingType.Base64 => Convert.ToBase64String(data),
315+
HashEncodingType.Base64Safe => ToBase64SafeString(data),
316+
_ => throw new ArgumentException($"Unsupported hash encoding: {encoding}")
317+
};
365318
}
366319

367320
public static string ComputeHash(string filepath)

0 commit comments

Comments
 (0)