88 lines
3.2 KiB
C#
88 lines
3.2 KiB
C#
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);
|
|
}
|
|
} |