Viewing is open to everyone. Downloading and starring need a GitHub sign-in. Sign in with GitHub

Native.cs

v0.1.0-build.85 Latest Commit ede38f5

Size
3.4 KB
Lines
86
Language
csharp
SHA-256
506435730da0…
View on GitHub

Sign in with GitHub to download. Each download is recorded with your GitHub username.

1using System;
2using System.Text;
3
4namespace OpenCKey.Interop
5{
6 /// <summary>Small helpers shared by the wrappers: ABI check, status checks, C strings.</summary>
7 internal static unsafe class Native
8 {
9 private static readonly object Gate = new object();
10 private static volatile bool _abiChecked;
11
12 /// <summary>
13 /// Verifies, once, that the loaded native library speaks the ABI these
14 /// struct mirrors were written for. A mismatched library would read
15 /// the structs at the wrong offsets, so it is refused outright.
16 /// </summary>
17 internal static void EnsureAbi()
18 {
19 if (_abiChecked) return;
20 lock (Gate)
21 {
22 if (_abiChecked) return;
23 uint abi;
24 try
25 {
26 abi = NativeMethods.ckey_get_abi_version();
27 }
28 catch (DllNotFoundException e)
29 {
30 throw new CKeyException(CKeyStatus.InternalError,
31 "The native ckey library was not found. The CKey package ships it for win-x64, linux-x64, " +
32 "osx-x64 and osx-arm64; for other platforms build sdk/dotnet/native with CMake. " + e.Message);
33 }
34 if (abi != NativeConstants.AbiVersion)
35 {
36 throw new CKeyException(CKeyStatus.InternalError,
37 $"The native ckey library has ABI version {abi}; this CKey assembly requires {NativeConstants.AbiVersion}.");
38 }
39 _abiChecked = true;
40 }
41 }
42
43 internal static void Check(int status, string what)
44 {
45 if (status != 0) throw new CKeyException((CKeyStatus)status, $"{what} failed: {(CKeyStatus)status}.");
46 }
47
48 internal static void Check(int status, string what, ref NativeDiagnostics diagnostics)
49 {
50 if (status == 0) return;
51 string message = Message(ref diagnostics);
52 throw new CKeyException((CKeyStatus)status,
53 string.IsNullOrEmpty(message) ? $"{what} failed: {(CKeyStatus)status}." : $"{what} failed: {message}");
54 }
55
56 internal static string Message(ref NativeDiagnostics diagnostics)
57 {
58 fixed (byte* m = diagnostics.Message) return FromUtf8Z(m, NativeConstants.DiagnosticsMessageBytes) ?? string.Empty;
59 }
60
61 /// <summary>Reads a NUL-terminated UTF-8 string of at most max bytes; null for a null pointer.</summary>
62 internal static string? FromUtf8Z(byte* p, int max = int.MaxValue)
63 {
64 if (p == null) return null;
65 int n = 0;
66 while (n < max && p[n] != 0) n++;
67 return n == 0 ? string.Empty : Encoding.UTF8.GetString(p, n);
68 }
69
70 /// <summary>UTF-8 bytes with a terminating NUL; null for null.</summary>
71 internal static byte[]? ToUtf8Z(string? s)
72 {
73 if (s == null) return null;
74 int n = Encoding.UTF8.GetByteCount(s);
75 var bytes = new byte[n + 1];
76 Encoding.UTF8.GetBytes(s, 0, s.Length, bytes, 0);
77 return bytes;
78 }
79
80 internal static int ToInt32Length(nuint length, string what)
81 {
82 if (length > int.MaxValue) throw new CKeyException(CKeyStatus.InsufficientBuffer, $"{what} needs more than 2 GiB.");
83 return (int)length;
84 }
85 }
86}