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();
}
}
}