Vanara/UnitTests/PInvoke/Cabinet/CabinetTests.cs

222 lines
7.3 KiB
C#

using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Collections.Generic;
using System.IO;
using Vanara.RunTimeLib;
using static Vanara.PInvoke.Cabinet;
using static Vanara.PInvoke.Kernel32;
namespace Vanara.PInvoke.Tests;
[TestFixture]
public class FDITests
{
private const string cabfn = "test.cab";
private static readonly string cabdir = TestCaseSources.TempDirWhack;
private ERF fderf = new();
private SafeHFDI? hfdi;
[OneTimeSetUp]
public void _Setup()
{
hfdi = FDICreate(AllocCallback, FreeCallback, OpenCallback, ReadCallback, WriteCallback, CloseCallback, SeekCallback, FDICPU.cpuUNKNOWN, ref fderf);
}
[OneTimeTearDown]
public void _TearDown()
{
hfdi?.Dispose();
}
[Test]
public void FCICreateTest()
{
SafeHFCI h;
ERF myerf = new();
using var tmp = new TempFile(null);
CCAB ccab = new(tmp.FullName);
Assert.That(h = FCICreate(ref myerf, FilePlacedCallback, AllocCallback, FreeCallback, FcOpenCallback, FcReadCallback, FcWriteCallback, FcCloseCallback, FcSeekCallback, DeleteCallback, GetTemplateCallback, ccab), ResultIs.ValidHandle);
Assert.That(FCIAddFile(h, TestCaseSources.SmallFile, Path.GetFileName(TestCaseSources.SmallFile), false, FcGetNextCab, FcStatus, FcGetOpenInfo, TCOMP.tcompTYPE_MSZIP), ResultIs.Successful);
Assert.That(FCIAddFile(h, TestCaseSources.ImageFile, Path.GetFileName(TestCaseSources.ImageFile), false, FcGetNextCab, FcStatus, FcGetOpenInfo, TCOMP.tcompTYPE_MSZIP), ResultIs.Successful);
Assert.That(FCIAddFile(h, TestCaseSources.WordDoc, Path.GetFileName(TestCaseSources.WordDoc), false, FcGetNextCab, FcStatus, FcGetOpenInfo, TCOMP.tcompTYPE_MSZIP), ResultIs.Successful);
Assert.That(FCIFlushFolder(h, FcGetNextCab, FcStatus), ResultIs.Successful);
Assert.That(FCIFlushCabinet(h, false, FcGetNextCab, FcStatus), ResultIs.Successful);
Assert.That(() => h?.Dispose(), Throws.Nothing);
Assert.That(File.Exists(tmp.FullName), Is.True);
}
[Test, MTAThread]
public void FDICopyTest()
{
List<string> files = new();
Assert.That(FDICopy(hfdi!, cabfn, cabdir, 0, Notify), Is.True);
Assert.That(files.Count, Is.GreaterThan(0));
files.WriteValues();
IntPtr Notify(FDINOTIFICATIONTYPE fdint, ref FDINOTIFICATION pfdin)
{
switch (fdint)
{
case FDINOTIFICATIONTYPE.fdintCOPY_FILE:
files.Add($"{pfdin.psz1} : {pfdin.cb} : {pfdin.DateTime}");
break;
default:
break;
}
return IntPtr.Zero;
}
}
[Test]
public void FDICreateTest()
{
SafeHFDI h;
ERF myerf = new();
Assert.That(h = FDICreate(AllocCallback, FreeCallback, OpenCallback, ReadCallback, WriteCallback, CloseCallback, SeekCallback, FDICPU.cpuUNKNOWN, ref myerf), ResultIs.ValidHandle);
Assert.That(() => h?.Dispose(), Throws.Nothing);
}
private IntPtr AllocCallback(uint cb) => Marshal.AllocHGlobal((int)cb);
private int CloseCallback(IntPtr hf) => FcCloseCallback(hf, out _, default);
private int DeleteCallback(string pszFile, out int err, IntPtr pv)
{
if (DeleteFile(pszFile))
{
err = 0;
return 0;
}
else
{
err = (int)(uint)GetLastError();
return -1;
}
}
private int FcCloseCallback(IntPtr hf, out int err, IntPtr pv)
{
err = 0;
if (CloseHandle(hf))
return 0;
err = (int)(uint)GetLastError();
return -1;
}
private bool FcGetNextCab(ref CCAB pccab, uint cbPrevCab, IntPtr pv) => true;
private IntPtr FcGetOpenInfo(string pszName, ref ushort pdate, ref ushort ptime, ref ushort pattribs, out int err, IntPtr pv)
{
err = 0;
var handle = CreateFile(pszName, Kernel32.FileAccess.GENERIC_READ, FileShare.ReadWrite, default, FileMode.Open, 0, default);
if (handle.IsInvalid)
{
err = (int)(uint)GetLastError();
return new IntPtr(-1);
}
if (!GetFileInformationByHandle(handle, out var info))
{
err = (int)(uint)GetLastError();
handle.Dispose();
return new IntPtr(-1);
}
FileTimeToDosDateTime(info.ftLastWriteTime, out pdate, out ptime);
pattribs = (ushort)(info.dwFileAttributes & (FileFlagsAndAttributes.FILE_ATTRIBUTE_READONLY | FileFlagsAndAttributes.FILE_ATTRIBUTE_HIDDEN | FileFlagsAndAttributes.FILE_ATTRIBUTE_SYSTEM | FileFlagsAndAttributes.FILE_ATTRIBUTE_ARCHIVE));
return handle.ReleaseOwnership();
}
private IntPtr FcOpenCallback(string pszFile, FileOpConstant oflag, FilePermissionConstant pmode, out int err, IntPtr pv)
{
FileMode creation;
FileShare sharing = pmode.ToFileShare();
Kernel32.FileAccess ioflag = 0;
switch (oflag & (FileOpConstant)0x03)
{
case FileOpConstant._O_RDONLY: ioflag |= Kernel32.FileAccess.GENERIC_READ; break;
case FileOpConstant._O_WRONLY: ioflag |= Kernel32.FileAccess.GENERIC_WRITE; break;
case FileOpConstant._O_RDWR: ioflag |= Kernel32.FileAccess.GENERIC_READ | Kernel32.FileAccess.GENERIC_WRITE; break;
}
if (oflag.IsFlagSet(FileOpConstant._O_CREAT))
{
if (oflag.IsFlagSet(FileOpConstant._O_EXCL)) creation = FileMode.CreateNew;
else if (oflag.IsFlagSet(FileOpConstant._O_TRUNC)) creation = FileMode.Create;
else creation = FileMode.OpenOrCreate;
}
else
{
if (oflag.IsFlagSet(FileOpConstant._O_TRUNC)) creation = FileMode.Create;
else creation = FileMode.Open;
}
var hfile = CreateFile(pszFile, ioflag, sharing, default, creation, FileFlagsAndAttributes.FILE_ATTRIBUTE_NORMAL, default).ReleaseOwnership();
err = hfile == HFILE.INVALID_HANDLE_VALUE ? (int)(uint)GetLastError() : 0;
return hfile == HFILE.INVALID_HANDLE_VALUE ? IntPtr.Zero : hfile;
}
private uint FcReadCallback(IntPtr hf, IntPtr memory, uint cb, out int err, IntPtr pv)
{
err = 0;
if (ReadFile(hf, memory, cb, out var read))
return read;
err = (int)(uint)GetLastError();
return unchecked((uint)-1);
}
private int FcSeekCallback(IntPtr hf, int dist, SeekOrigin seektype, out int err, IntPtr pv)
{
var ret = SetFilePointer(hf, dist, default, seektype);
if (ret == INVALID_SET_FILE_POINTER)
{
err = (int)(uint)GetLastError();
return -1;
}
err = 0;
return unchecked((int)ret);
}
private int FcStatus(CabinetFileStatus typeStatus, uint cb1, uint cb2, IntPtr pv) => 0;
private uint FcWriteCallback(IntPtr hf, IntPtr memory, uint cb, out int err, IntPtr pv)
{
err = 0;
if (WriteFile(hf, memory, cb, out var written))
return written;
err = (int)(uint)GetLastError();
return unchecked((uint)-1);
}
private int FilePlacedCallback(ref CCAB pccab, string pszFile, int cbFile, bool fContinuation, IntPtr pv)
{
if (!fContinuation)
TestContext.WriteLine($"Adding {pszFile}...");
return 0;
}
private void FreeCallback(IntPtr memory) => Marshal.FreeHGlobal(memory);
private bool GetTemplateCallback(IntPtr pszTempName, int cbTempName, IntPtr pv)
{
var sb = new StringBuilder(1024);
GetTempFileName(Path.GetTempPath(), "cab", 0, sb);
if (sb.Length >= cbTempName)
return false;
Marshal.Copy(StringHelper.GetBytes(sb.ToString(), true, CharSet.Ansi), 0, pszTempName, sb.Length + 1);
return DeleteFile(sb.ToString());
}
private IntPtr OpenCallback(string pszFile, FileOpConstant oflag, FilePermissionConstant pmode) => FcOpenCallback(pszFile, oflag, pmode, out _, default);
private uint ReadCallback(IntPtr hf, IntPtr memory, uint cb) => FcReadCallback(hf, memory, cb, out _, default);
private int SeekCallback(IntPtr hf, int dist, SeekOrigin seektype) => FcSeekCallback(hf, dist, seektype, out _, default);
private uint WriteCallback(IntPtr hf, IntPtr memory, uint cb) => FcWriteCallback(hf, memory, cb, out _, default);
}