mirror of
				https://github.com/velopack/velopack.git
				synced 2025-10-25 15:19:22 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			203 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			203 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| // Licensed to the .NET Foundation under one or more agreements.
 | |
| // The .NET Foundation licenses this file to you under the MIT license.
 | |
| 
 | |
| using System;
 | |
| using System.IO;
 | |
| using System.IO.MemoryMappedFiles;
 | |
| 
 | |
| namespace Microsoft.NET.HostModel.AppHost
 | |
| {
 | |
|     public static class BinaryUtils
 | |
|     {
 | |
|         internal static unsafe void SearchAndReplace(
 | |
|             MemoryMappedViewAccessor accessor,
 | |
|             byte[] searchPattern,
 | |
|             byte[] patternToReplace,
 | |
|             bool pad0s = true)
 | |
|         {
 | |
|             byte* pointer = null;
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 accessor.SafeMemoryMappedViewHandle.AcquirePointer(ref pointer);
 | |
|                 byte* bytes = pointer + accessor.PointerOffset;
 | |
| 
 | |
|                 int position = KMPSearch(searchPattern, bytes, accessor.Capacity);
 | |
|                 if (position < 0)
 | |
|                 {
 | |
|                     throw new PlaceHolderNotFoundInAppHostException(searchPattern);
 | |
|                 }
 | |
| 
 | |
|                 accessor.WriteArray(
 | |
|                     position: position,
 | |
|                     array: patternToReplace,
 | |
|                     offset: 0,
 | |
|                     count: patternToReplace.Length);
 | |
| 
 | |
|                 if (pad0s)
 | |
|                 {
 | |
|                     Pad0(searchPattern, patternToReplace, bytes, position);
 | |
|                 }
 | |
|             }
 | |
|             finally
 | |
|             {
 | |
|                 if (pointer != null)
 | |
|                 {
 | |
|                     accessor.SafeMemoryMappedViewHandle.ReleasePointer();
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private static unsafe void Pad0(byte[] searchPattern, byte[] patternToReplace, byte* bytes, int offset)
 | |
|         {
 | |
|             if (patternToReplace.Length < searchPattern.Length)
 | |
|             {
 | |
|                 for (int i = patternToReplace.Length; i < searchPattern.Length; i++)
 | |
|                 {
 | |
|                     bytes[i + offset] = 0x0;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public static unsafe void SearchAndReplace(
 | |
|             string filePath,
 | |
|             byte[] searchPattern,
 | |
|             byte[] patternToReplace,
 | |
|             bool pad0s = true)
 | |
|         {
 | |
|             using (var mappedFile = MemoryMappedFile.CreateFromFile(filePath))
 | |
|             {
 | |
|                 using (var accessor = mappedFile.CreateViewAccessor())
 | |
|                 {
 | |
|                     SearchAndReplace(accessor, searchPattern, patternToReplace, pad0s);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         internal static unsafe int SearchInFile(MemoryMappedViewAccessor accessor, byte[] searchPattern)
 | |
|         {
 | |
|             var safeBuffer = accessor.SafeMemoryMappedViewHandle;
 | |
|             return KMPSearch(searchPattern, (byte*)safeBuffer.DangerousGetHandle(), (int)safeBuffer.ByteLength);
 | |
|         }
 | |
| 
 | |
|         public static unsafe int SearchInFile(string filePath, byte[] searchPattern)
 | |
|         {
 | |
|             using (var mappedFile = MemoryMappedFile.CreateFromFile(filePath))
 | |
|             {
 | |
|                 using (var accessor = mappedFile.CreateViewAccessor(0, 0, MemoryMappedFileAccess.Read))
 | |
|                 {
 | |
|                     return SearchInFile(accessor, searchPattern);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // See: https://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm
 | |
|         private static int[] ComputeKMPFailureFunction(byte[] pattern)
 | |
|         {
 | |
|             int[] table = new int[pattern.Length];
 | |
|             if (pattern.Length >= 1)
 | |
|             {
 | |
|                 table[0] = -1;
 | |
|             }
 | |
|             if (pattern.Length >= 2)
 | |
|             {
 | |
|                 table[1] = 0;
 | |
|             }
 | |
| 
 | |
|             int pos = 2;
 | |
|             int cnd = 0;
 | |
|             while (pos < pattern.Length)
 | |
|             {
 | |
|                 if (pattern[pos - 1] == pattern[cnd])
 | |
|                 {
 | |
|                     table[pos] = cnd + 1;
 | |
|                     cnd++;
 | |
|                     pos++;
 | |
|                 }
 | |
|                 else if (cnd > 0)
 | |
|                 {
 | |
|                     cnd = table[cnd];
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     table[pos] = 0;
 | |
|                     pos++;
 | |
|                 }
 | |
|             }
 | |
|             return table;
 | |
|         }
 | |
| 
 | |
|         // See: https://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm
 | |
|         private static unsafe int KMPSearch(byte[] pattern, byte* bytes, long bytesLength)
 | |
|         {
 | |
|             int m = 0;
 | |
|             int i = 0;
 | |
|             int[] table = ComputeKMPFailureFunction(pattern);
 | |
| 
 | |
|             while (m + i < bytesLength)
 | |
|             {
 | |
|                 if (pattern[i] == bytes[m + i])
 | |
|                 {
 | |
|                     if (i == pattern.Length - 1)
 | |
|                     {
 | |
|                         return m;
 | |
|                     }
 | |
|                     i++;
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     if (table[i] > -1)
 | |
|                     {
 | |
|                         m = m + i - table[i];
 | |
|                         i = table[i];
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         m++;
 | |
|                         i = 0;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return -1;
 | |
|         }
 | |
| 
 | |
|         public static void CopyFile(string sourcePath, string destinationPath)
 | |
|         {
 | |
|             var destinationDirectory = new FileInfo(destinationPath).Directory.FullName;
 | |
|             if (!Directory.Exists(destinationDirectory))
 | |
|             {
 | |
|                 Directory.CreateDirectory(destinationDirectory);
 | |
|             }
 | |
| 
 | |
|             // Copy file to destination path so it inherits the same attributes/permissions.
 | |
|             File.Copy(sourcePath, destinationPath, overwrite: true);
 | |
|         }
 | |
| 
 | |
|         internal static void WriteToStream(MemoryMappedViewAccessor sourceViewAccessor, FileStream fileStream, long length)
 | |
|         {
 | |
|             int pos = 0;
 | |
|             int bufSize = 16384; //16K
 | |
| 
 | |
|             byte[] buf = new byte[bufSize];
 | |
|             length = Math.Min(length, sourceViewAccessor.Capacity);
 | |
|             do
 | |
|             {
 | |
|                 int bytesRequested = Math.Min((int)length - pos, bufSize);
 | |
|                 if (bytesRequested <= 0)
 | |
|                 {
 | |
|                     break;
 | |
|                 }
 | |
| 
 | |
|                 int bytesRead = sourceViewAccessor.ReadArray(pos, buf, 0, bytesRequested);
 | |
|                 if (bytesRead > 0)
 | |
|                 {
 | |
|                     fileStream.Write(buf, 0, bytesRead);
 | |
|                     pos += bytesRead;
 | |
|                 }
 | |
|             }
 | |
|             while (true);
 | |
|         }
 | |
|     }
 | |
| }
 |