Skip to content
This repository was archived by the owner on Jul 26, 2023. It is now read-only.

Add cabinet API #471

Merged
merged 6 commits into from
Jul 1, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/Cabinet.Tests/Cabinet.Tests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net472;netcoreapp2.1</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Cabinet\Cabinet.csproj" />
<ProjectReference Include="..\Kernel32\Kernel32.csproj" />
<ProjectReference Include="..\Windows.Core\Windows.Core.csproj" />
</ItemGroup>
</Project>
104 changes: 104 additions & 0 deletions src/Cabinet.Tests/CabinetFacts.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Copyright © .NET Foundation and Contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.IO;
using System.Runtime.InteropServices;
using PInvoke;
using Xunit;

public unsafe class CabinetFacts : IDisposable
{
private readonly Cabinet.FNALLOC fdiAllocMemDelegate;
private readonly Cabinet.FNFREE fdiFreeMemDelegate;
private readonly Cabinet.FNOPEN fdiOpenStreamDelegate;
private readonly Cabinet.FNREAD fdiReadStreamDelegate;
private readonly Cabinet.FNWRITE fdiWriteStreamDelegate;
private readonly Cabinet.FNCLOSE fdiCloseStreamDelegate;
private readonly Cabinet.FNSEEK fdiSeekStreamDelegate;

private readonly Cabinet.ERF* erf;

public CabinetFacts()
{
this.erf = (Cabinet.ERF*)Marshal.AllocHGlobal(sizeof(Cabinet.ERF));

this.fdiAllocMemDelegate = this.AllocMem;
this.fdiFreeMemDelegate = this.FreeMem;
this.fdiOpenStreamDelegate = this.Open;
this.fdiReadStreamDelegate = this.Read;
this.fdiWriteStreamDelegate = this.Write;
this.fdiCloseStreamDelegate = this.Close;
this.fdiSeekStreamDelegate = this.Seek;
}

[Fact]
public void CreateDisposeContext()
{
var handle = Cabinet.FDICreate(
this.fdiAllocMemDelegate,
this.fdiFreeMemDelegate,
this.fdiOpenStreamDelegate,
this.fdiReadStreamDelegate,
this.fdiWriteStreamDelegate,
this.fdiCloseStreamDelegate,
this.fdiSeekStreamDelegate,
Cabinet.CpuType.Unknown,
this.erf);

handle.Dispose();
}

public void Dispose()
{
Marshal.FreeHGlobal((IntPtr)this.erf);
}

private IntPtr AllocMem(int byteCount) => Marshal.AllocHGlobal((IntPtr)byteCount);

private void FreeMem(IntPtr memPointer) => Marshal.FreeHGlobal(memPointer);

private int Open(string path, int openFlags, int shareMode)
{
var handle = Kernel32.CreateFile(path, (Kernel32.ACCESS_MASK)Kernel32.ACCESS_MASK.GenericRight.GENERIC_READ, Kernel32.FileShare.FILE_SHARE_READ, IntPtr.Zero, Kernel32.CreationDisposition.OPEN_EXISTING, Kernel32.CreateFileFlags.FILE_ATTRIBUTE_NORMAL, Kernel32.SafeObjectHandle.Null);
return (int)handle.DangerousGetHandle();
}

private int Read(int streamHandle, void* memory, int cb)
{
int? read = 0;
Kernel32.ReadFile(
new Kernel32.SafeObjectHandle(new IntPtr(streamHandle), ownsHandle: false),
memory,
cb,
ref read,
null);
return read.Value;
}

private int Write(int streamHandle, void* memory, int cb)
{
int? written = 0;
Kernel32.WriteFile(
new Kernel32.SafeObjectHandle(new IntPtr(streamHandle), ownsHandle: false),
memory,
cb,
ref written,
null);
return written.Value;
}

private uint Seek(int streamHandle, int offset, SeekOrigin seekOrigin)
{
return Kernel32.SetFilePointer(
new Kernel32.SafeObjectHandle(new IntPtr(streamHandle)),
offset,
out long _,
seekOrigin) ? 0u : 1u;
}

private uint Close(int streamHandle)
{
return Kernel32.CloseHandle(new IntPtr(streamHandle)) ? 0u : 1u;
}
}
36 changes: 36 additions & 0 deletions src/Cabinet/Cabinet+CpuType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright © .NET Foundation and Contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace PInvoke
{
using System.Diagnostics.CodeAnalysis;

/// <content>
/// Contains the <see cref="CpuType"/> nested type.
/// </content>
public partial class Cabinet
{
/// <summary>
/// In the 16-bit version of FDI, specifies the CPU type and can be any of the following values.
/// </summary>
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1300:Element must begin with upper-case letter", Justification = "Native naming convention")]

public enum CpuType : int
{
/// <summary>
/// FDI should determine the CPU type.
/// </summary>
Unknown = -1,

/// <summary>
/// Only 80286 instructions can be used.
/// </summary>
_80286 = 0,

/// <summary>
/// 80386 instructions can be used.
/// </summary>
_80386 = 1,
}
}
}
33 changes: 33 additions & 0 deletions src/Cabinet/Cabinet+ERF.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright © .NET Foundation and Contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace PInvoke
{
/// <content>
/// Contains the <see cref="ERF"/> nested type.
/// </content>
public partial class Cabinet
{
/// <summary>
/// The ERF structure contains error information from FCI/FDI. The caller should not modify this structure.
/// </summary>
/// <seealso href="https://docs.microsoft.com/en-us/windows/win32/api/fdi_fci_types/ns-fdi_fci_types-erf"/>
public struct ERF
{
/// <summary>
/// An FCI/FDI error code.
/// </summary>
public FdiError Oper;

/// <summary>
/// An optional error value filled in by FCI/FDI. For FCI, this is usually the C runtime errno value.
/// </summary>
public int Type;

/// <summary>
/// A flag that indicates an error. If <see langword="true"/>, an error is present.
/// </summary>
public int Error;
}
}
}
78 changes: 78 additions & 0 deletions src/Cabinet/Cabinet+FdiError.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright © .NET Foundation and Contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace PInvoke
{
/// <content>
/// Contains the <see cref="FdiError"/> nested type.
/// </content>
public partial class Cabinet
{
/// <summary>
/// Error values for FDI.
/// </summary>
/// <seealso href="https://docs.microsoft.com/en-us/windows/win32/api/fdi_fci_types/ns-fdi_fci_types-erf#members"/>
public enum FdiError : int
{
/// <summary>
/// No error.
/// </summary>
FDIERROR_NONE = 0x00,

/// <summary>
/// The cabinet file was not found.
/// </summary>
FDIERROR_CABINET_NOT_FOUND = 0x01,

/// <summary>
/// The cabinet file does not have the correct format.
/// </summary>
FDIERROR_NOT_A_CABINET = 0x02,

/// <summary>
/// The cabinet file has an unknown version number.
/// </summary>
FDIERROR_UNKNOWN_CABINET_VERSION = 0x03,

/// <summary>
/// The cabinet file is corrupt.
/// </summary>
FDIERROR_CORRUPT_CABINET = 0x04,

/// <summary>
/// Insufficient memory.
/// </summary>
FDIERROR_ALLOC_FAIL = 0x05,

/// <summary>
/// Unknown compression type used in the cabinet folder.
/// </summary>
FDIERROR_BAD_COMPR_TYPE = 0x06,

/// <summary>
/// Failure decompressing data from the cabinet file.
/// </summary>
FDIERROR_MDI_FAIL = 0x07,

/// <summary>
/// Failure writing to the target file.
/// </summary>
FDIERROR_TARGET_FILE = 0x08,

/// <summary>
/// The cabinets within a set do not have the same RESERVE sizes.
/// </summary>
FDIERROR_RESERVE_MISMATCH = 0x09,

/// <summary>
/// The cabinet returned by fdintNEXT_CABINET is incorrect.
/// </summary>
FDIERROR_WRONG_CABINET = 0x0A,

/// <summary>
/// FDI aborted.
/// </summary>
FDIERROR_USER_ABORT = 0x0B,
}
}
}
33 changes: 33 additions & 0 deletions src/Cabinet/Cabinet+FdiHandle.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright © .NET Foundation and Contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace PInvoke
{
using Microsoft.Win32.SafeHandles;

/// <content>
/// Contains the <see cref="FdiHandle"/> nested type.
/// </content>
public partial class Cabinet
{
/// <summary>
/// Represents a handle used by the FDI API.
/// </summary>
public class FdiHandle : SafeHandleZeroOrMinusOneIsInvalid
{
/// <summary>
/// Initializes a new instance of the <see cref="FdiHandle"/> class.
/// </summary>
public FdiHandle()
: base(true)
{
}

/// <inheritdoc/>
protected override bool ReleaseHandle()
{
return Cabinet.FDIDestroy(this.handle);
}
}
}
}
84 changes: 84 additions & 0 deletions src/Cabinet/Cabinet+NOTIFICATION.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Copyright © .NET Foundation and Contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace PInvoke
{
using System;

/// <content>
/// Contains the <see cref="NOTIFICATION"/> nested type.
/// </content>
public partial class Cabinet
{
/// <summary>
/// Cabinet notification details passed to the FDI Notify callback.
/// </summary>
public unsafe struct NOTIFICATION
{
/// <summary>
/// The size, in bytes, of a cabinet element.
/// </summary>
public int cb;

/// <summary>
/// A null-terminated string.
/// </summary>
public char* psz1;

/// <summary>
/// A null-terminated string.
/// </summary>
public char* psz2;

/// <summary>
/// A null-terminated string.
/// </summary>
public char* psz3;

/// <summary>
/// Pointer to an application-defined value.
/// </summary>
public IntPtr pv;

/// <summary>
/// Application-defined value used to identify the opened file.
/// </summary>
public IntPtr hf;

/// <summary>
/// The MS-DOS date when the cabinet file was last modified.
/// </summary>
public ushort date;

/// <summary>
/// The MS-DOS time when the cabinet file was last modified.
/// </summary>
public ushort time;

/// <summary>
/// The file attributes.
/// </summary>
public short attribs;

/// <summary>
/// The identifier for a cabinet set.
/// </summary>
public short setID;

/// <summary>
/// The number of the cabinets within a set.
/// </summary>
public short iCabinet;

/// <summary>
/// The number of folders within a cabinet.
/// </summary>
public short iFolder;

/// <summary>
/// An FDI error code.
/// </summary>
public FdiError fdie;
}
}
}
Loading