@@ -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