Checkpoint

This commit is contained in:
2020-05-01 05:08:04 -04:00
parent abba062f4f
commit 1a394ddb31
20 changed files with 239 additions and 102 deletions

View File

@@ -0,0 +1,88 @@
using System;
using System.Buffers;
using System.Runtime.InteropServices;
using System.Text;
namespace Foodsoft.Alpm.Interop
{
internal static class CFormatter
{
private static readonly int vaListCopyNWords;
private static readonly Vsnprintf? vsnprintfFunc;
static CFormatter()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ||
RuntimeInformation.IsOSPlatform(OSPlatform.FreeBSD))
{
vaListCopyNWords = RuntimeInformation.ProcessArchitecture switch
{
Architecture.X86 => 1,
Architecture.X64 => 3,
Architecture.Arm => 1,
Architecture.Arm64 => 4,
_ => vaListCopyNWords
};
vsnprintfFunc = vsnprintfLibc;
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
vaListCopyNWords = 1;
vsnprintfFunc = vsnprintfUCrt;
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
vaListCopyNWords = RuntimeInformation.ProcessArchitecture switch
{
Architecture.X86 => 1,
Architecture.X64 => 3,
Architecture.Arm => 1,
Architecture.Arm64 => 1,
_ => vaListCopyNWords
};
vsnprintfFunc = vsnprintfLibc;
}
}
internal static unsafe string Format(IntPtr format, IntPtr vaList)
{
const int bufSize = 256;
if (vsnprintfFunc == null || vaListCopyNWords <= 0)
return "[Formatter unsupported for platform]";
var vaListBuf = (void**) vaList;
var vaListCopy = stackalloc void*[vaListCopyNWords];
for (var i = 0; i < vaListCopyNWords; i++) vaListCopy[i] = vaListBuf[i];
var strBuf = stackalloc byte[bufSize];
var strBufPtr = (IntPtr) strBuf;
var nbNeed = vsnprintfFunc(strBufPtr, (UIntPtr) bufSize, format, vaList);
if (nbNeed < bufSize)
return Marshal.PtrToStringUTF8(strBufPtr, nbNeed);
var pool = ArrayPool<byte>.Shared;
var buffer = pool.Rent(nbNeed + 1);
fixed (byte* pb = buffer)
{
nbNeed = vsnprintfFunc((IntPtr) pb, (UIntPtr) buffer.Length, format, (IntPtr) vaListCopy);
}
var result = Encoding.UTF8.GetString(buffer, 0, nbNeed);
pool.Return(buffer);
return result;
}
private delegate int Vsnprintf(IntPtr buffer, UIntPtr size, IntPtr format, IntPtr args);
[DllImport("libc", EntryPoint = "vsnprintf", CallingConvention = CallingConvention.Cdecl)]
internal static extern int vsnprintfLibc(IntPtr buffer, UIntPtr size, IntPtr format, IntPtr args);
[DllImport("ucrt", EntryPoint = "vsnprintf", CallingConvention = CallingConvention.Cdecl)]
internal static extern int vsnprintfUCrt(IntPtr buffer, UIntPtr size, IntPtr format, IntPtr args);
}
}

42
Alpm/Interop/UTF8In.cs Normal file
View File

@@ -0,0 +1,42 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using JetBrains.Annotations;
namespace Foodsoft.Alpm.Marshalling
{
internal readonly struct UTF8In : ICustomMarshaler
{
private static readonly UTF8In _instance = default;
public void CleanUpManagedData(object managedObj) { }
public void CleanUpNativeData(IntPtr pNativeData)
{
if (pNativeData == IntPtr.Zero)
return;
Marshal.FreeCoTaskMem(pNativeData);
}
public int GetNativeDataSize()
{
return -1;
}
public IntPtr MarshalManagedToNative(object? managedObj)
{
return Marshal.StringToCoTaskMemUTF8((string?) managedObj);
}
public object MarshalNativeToManaged(IntPtr pNativeData)
{
return Marshal.PtrToStringUTF8(pNativeData)!;
}
[UsedImplicitly]
private static ICustomMarshaler GetInstance(string cookie)
{
return _instance;
}
}
}

View File

@@ -0,0 +1,36 @@
using System;
using System.Runtime.InteropServices;
using JetBrains.Annotations;
namespace Foodsoft.Alpm.Marshalling
{
internal readonly struct UTF8Return : ICustomMarshaler
{
private static readonly UTF8Return _instance = default;
[UsedImplicitly]
private static ICustomMarshaler GetInstance(string cookie)
{
return _instance;
}
public void CleanUpManagedData(object managedObj) { }
public void CleanUpNativeData(IntPtr pNativeData) { }
public int GetNativeDataSize()
{
return -1;
}
public object MarshalNativeToManaged(IntPtr pNativeData)
{
return Marshal.PtrToStringUTF8(pNativeData)!;
}
public IntPtr MarshalManagedToNative(object managedObj)
{
throw new NotImplementedException();
}
}
}