Checkpoint
This commit is contained in:
88
Alpm/Interop/CFormatter.cs
Normal file
88
Alpm/Interop/CFormatter.cs
Normal 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
42
Alpm/Interop/UTF8In.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
36
Alpm/Interop/UTF8Return.cs
Normal file
36
Alpm/Interop/UTF8Return.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user