using System; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using System.Runtime.Versioning; namespace Velopack.Compression { [ExcludeFromCodeCoverage] [SupportedOSPlatform("windows")] internal class MsDeltaCompression { /// /// The ApplyDelta function use the specified delta and source files to create a new copy of the target file. /// /// Either DELTA_FLAG_NONE or DELTA_APPLY_FLAG_ALLOW_PA19. /// The name of the source file to which the delta is to be applied. /// The name of the delta to be applied to the source file. /// The name of the target file that is to be created. /// /// Returns TRUE on success or FALSE otherwise. /// /// /// http://msdn.microsoft.com/library/bb417345.aspx#applydeltaaw /// [DllImport("msdelta.dll", CharSet = CharSet.Unicode, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool ApplyDelta( [MarshalAs(UnmanagedType.I8)] ApplyFlags applyFlags, string sourceName, string deltaName, string targetName); /// /// The CreateDelta function creates a delta from the specified source and target files and write the output delta to the designated file name. /// /// The file type set used for Create. /// The file type set used for Create. /// The file type set used for Create. /// The file type set used for Create. /// The name of the target against which the source is compared. /// Reserved. Pass NULL. /// Reserved. Pass NULL. /// Reserved. Pass a DELTA_INPUT structure with lpStart set to NULL and uSize set to 0. /// The time stamp set on the target file after delta Apply. If NULL, the timestamp of the target file during delta Create will be used. /// ALG_ID of the algorithm to be used to generate the target signature. /// The name of the delta file to be created. /// /// Returns TRUE on success or FALSE otherwise. /// /// /// http://msdn.microsoft.com/library/bb417345.aspx#createdeltaaw /// [DllImport("msdelta.dll", CharSet = CharSet.Unicode, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool CreateDelta( [MarshalAs(UnmanagedType.I8)] FileTypeSet fileTypeSet, [MarshalAs(UnmanagedType.I8)] CreateFlags setFlags, [MarshalAs(UnmanagedType.I8)] CreateFlags resetFlags, string sourceName, string targetName, string? sourceOptionsName, string? targetOptionsName, DeltaInput globalOptions, IntPtr targetFileTime, [MarshalAs(UnmanagedType.U4)] HashAlgId hashAlgId, string deltaName); private enum HashAlgId { /// No signature. None = 0, /// 32-bit CRC defined in msdelta.dll. Crc32 = 32, } /// /// http://msdn.microsoft.com/library/bb417345.aspx#deltaflagtypeflags /// private enum ApplyFlags : long { /// Indicates no special handling. None = 0, /// Allow MSDelta to apply deltas created using PatchAPI. AllowLegacy = 1, } /// /// http://msdn.microsoft.com/library/bb417345.aspx#filetypesets /// [Flags] private enum FileTypeSet : long { /// /// File type set that includes I386, IA64 and AMD64 Portable Executable (PE) files. Others are treated as raw. /// Executables = 0x0FL, } /// /// http://msdn.microsoft.com/library/bb417345.aspx#deltaflagtypeflags /// private enum CreateFlags : long { /// Indicates no special handling. None = 0, /// Allow the source, target and delta files to exceed the default size limit. IgnoreFileSizeLimit = 1 << 17, } /// /// http://msdn.microsoft.com/library/bb417345.aspx#deltainputstructure /// [StructLayout(LayoutKind.Sequential)] private struct DeltaInput { /// Memory address non-editable input buffer. public IntPtr Start; /// Size of the memory buffer in bytes. public IntPtr Size; /// /// Defines whether MSDelta is allowed to edit the input buffer. If you make the input editable, the buffer will /// be zeroed at function return. However this will cause most MSDelta functions to use less memory. /// [MarshalAs(UnmanagedType.Bool)] public bool Editable; } //public void CreateDelta(string oldFilePath, string newFilePath, string deltaFilePath) //{ // const string? sourceOptionsName = null; // const string? targetOptionsName = null; // var globalOptions = new DeltaInput(); // var targetFileTime = IntPtr.Zero; // if (!NativeMethods.CreateDelta( // FileTypeSet.Executables, CreateFlags.IgnoreFileSizeLimit, CreateFlags.None, oldFilePath, newFilePath, // sourceOptionsName, targetOptionsName, globalOptions, targetFileTime, HashAlgId.Crc32, deltaFilePath)) // { // throw new Win32Exception(); // } //} public static void ApplyDelta(string deltaFilePath, string oldFilePath, string newFilePath) { if (!ApplyDelta(ApplyFlags.AllowLegacy, oldFilePath, deltaFilePath, newFilePath)) throw new Win32Exception(); } } }