diff --git a/.idea/.idea.DotNetAplm.dir/.idea/.gitignore b/.idea/.idea.DotNetAplm.dir/.idea/.gitignore
new file mode 100644
index 0000000..4e0d79f
--- /dev/null
+++ b/.idea/.idea.DotNetAplm.dir/.idea/.gitignore
@@ -0,0 +1,13 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Rider ignored files
+/contentModel.xml
+/.idea.DotNetAplm.iml
+/projectSettingsUpdater.xml
+/modules.xml
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
+# Editor-based HTTP Client requests
+/httpRequests/
diff --git a/.idea/.idea.DotNetAplm.dir/.idea/.idea.DotNetAplm.dir.iml b/.idea/.idea.DotNetAplm.dir/.idea/.idea.DotNetAplm.dir.iml
new file mode 100644
index 0000000..e6bc2ca
--- /dev/null
+++ b/.idea/.idea.DotNetAplm.dir/.idea/.idea.DotNetAplm.dir.iml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.DotNetAplm.dir/.idea/encodings.xml b/.idea/.idea.DotNetAplm.dir/.idea/encodings.xml
new file mode 100644
index 0000000..df87cf9
--- /dev/null
+++ b/.idea/.idea.DotNetAplm.dir/.idea/encodings.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.DotNetAplm.dir/.idea/indexLayout.xml b/.idea/.idea.DotNetAplm.dir/.idea/indexLayout.xml
new file mode 100644
index 0000000..27ba142
--- /dev/null
+++ b/.idea/.idea.DotNetAplm.dir/.idea/indexLayout.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.DotNetAplm.dir/.idea/misc.xml b/.idea/.idea.DotNetAplm.dir/.idea/misc.xml
new file mode 100644
index 0000000..28a804d
--- /dev/null
+++ b/.idea/.idea.DotNetAplm.dir/.idea/misc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.DotNetAplm.dir/.idea/vcs.xml b/.idea/.idea.DotNetAplm.dir/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/.idea.DotNetAplm.dir/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.DotNetAplm.dir/riderModule.iml b/.idea/.idea.DotNetAplm.dir/riderModule.iml
new file mode 100644
index 0000000..1a4e0d9
--- /dev/null
+++ b/.idea/.idea.DotNetAplm.dir/riderModule.iml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/API.cs b/API.cs
new file mode 100644
index 0000000..9b781fd
--- /dev/null
+++ b/API.cs
@@ -0,0 +1,4 @@
+$HEADER$namespace $NAMESPACE$
+{
+ public class $CLASS$ {$END$}
+}
\ No newline at end of file
diff --git a/Alpm.cs b/AlpmOld.cs
similarity index 59%
rename from Alpm.cs
rename to AlpmOld.cs
index b956b06..16cd984 100644
--- a/Alpm.cs
+++ b/AlpmOld.cs
@@ -12,427 +12,12 @@ using System.Runtime.Serialization;
// ReSharper disable InconsistentNaming
-namespace nalpm
+namespace Alpm
{
- public enum errno_t
- {
- ERR_OK = 0,
- ERR_MEMORY,
- ERR_SYSTEM,
- ERR_BADPERMS,
- ERR_NOT_A_FILE,
- ERR_NOT_A_DIR,
- ERR_WRONG_ARGS,
- ERR_DISK_SPACE,
-
- /* Interface */
- ERR_HANDLE_NULL,
- ERR_HANDLE_NOT_NULL,
- ERR_HANDLE_LOCK,
-
- /* Databases */
- ERR_DB_OPEN,
- ERR_DB_CREATE,
- ERR_DB_NULL,
- ERR_DB_NOT_NULL,
- ERR_DB_NOT_FOUND,
- ERR_DB_INVALID,
- ERR_DB_INVALID_SIG,
- ERR_DB_VERSION,
- ERR_DB_WRITE,
- ERR_DB_REMOVE,
-
- /* Servers */
- ERR_SERVER_BAD_URL,
- ERR_SERVER_NONE,
-
- /* Transactions */
- ERR_TRANS_NOT_NULL,
- ERR_TRANS_NULL,
- ERR_TRANS_DUP_TARGET,
- ERR_TRANS_NOT_INITIALIZED,
- ERR_TRANS_NOT_PREPARED,
- ERR_TRANS_ABORT,
- ERR_TRANS_TYPE,
- ERR_TRANS_NOT_LOCKED,
- ERR_TRANS_HOOK_FAILED,
-
- /* Packages */
- ERR_PKG_NOT_FOUND,
- ERR_PKG_IGNORED,
- ERR_PKG_INVALID,
- ERR_PKG_INVALID_CHECKSUM,
- ERR_PKG_INVALID_SIG,
- ERR_PKG_MISSING_SIG,
- ERR_PKG_OPEN,
- ERR_PKG_CANT_REMOVE,
- ERR_PKG_INVALID_NAME,
- ERR_PKG_INVALID_ARCH,
- ERR_PKG_REPO_NOT_FOUND,
-
- /* Signatures */
- ERR_SIG_MISSING,
- ERR_SIG_INVALID,
-
- /* Dependencies */
- ERR_UNSATISFIED_DEPS,
- ERR_CONFLICTING_DEPS,
- ERR_FILE_CONFLICTS,
-
- /* Misc */
- ERR_RETRIEVE,
- ERR_INVALID_REGEX,
-
- /* External library errors */
- ERR_LIBARCHIVE,
- ERR_LIBCURL,
- ERR_EXTERNAL_DOWNLOAD,
- ERR_GPGME,
-
- /* Missing compile-time features */
- ERR_MISSING_CAPABILITY_SIGNATURES
- }
-
- /** Package install reasons. */
- enum alpm_pkgreason_t
- {
- /** Explicitly requested by the user. */
- PKG_REASON_EXPLICIT = 0,
-
- /** Installed as a dependency for another package. */
- PKG_REASON_DEPEND = 1
- }
- /** Location a package object was loaded from. */
- enum alpm_pkgfrom_t
- {
- PKG_FROM_FILE = 1,
- PKG_FROM_LOCALDB,
- PKG_FROM_SYNCDB
- }
-
- /** Method used to validate a package. */
- enum alpm_pkgvalidation_t
- {
- PKG_VALIDATION_UNKNOWN = 0,
- PKG_VALIDATION_NONE = (1 << 0),
- PKG_VALIDATION_MD5SUM = (1 << 1),
- PKG_VALIDATION_SHA256SUM = (1 << 2),
- PKG_VALIDATION_SIGNATURE = (1 << 3)
- }
-
- /** Types of version constraints in dependency specs. */
- public enum alpm_depmod_t
- {
- /** No version constraint */
- DEP_MOD_ANY = 1,
-
- /** Test version equality (package=x.y.z) */
- DEP_MOD_EQ,
-
- /** Test for at least a version (package>=x.y.z) */
- DEP_MOD_GE,
-
- /** Test for at most a version (package<=x.y.z) */
- DEP_MOD_LE,
-
- /** Test for greater than some version (package>x.y.z) */
- DEP_MOD_GT,
-
- /** Test for less than some version (package(ptr);
- }
- }
-
- /** Missing dependency */
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
- public struct alpm_depmissing_t
- {
- public string target;
-
- public AlpmDependPtr depend;
-
- /* this is used only in the case of a remove dependency error */
- public string causingpkg;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- /** Conflict */
- public struct alpm_conflict_t
- {
- public ulong package1_hash;
- public ulong package2_hash;
- public string package1;
- public string package2;
- public AlpmDependPtr reason;
- }
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
- /** File conflict */
- struct alpm_fileconflict_t
- {
- public string target;
- public alpm_fileconflicttype_t type;
- public string file;
- public string ctarget;
- }
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
- /** Package group */
- public readonly struct alpm_group_t
- {
- /** group name */
- public readonly string name;
-
- /** list of alpm_pkg_t packages */
- public readonly unsafe alpm_list_t* packages;
- }
-
- /* TODO: alpm_pkg_get_files - need to wrap */
- /** File in a package */
- public readonly struct alpm_file_t
- {
- public readonly string name;
- public readonly UIntPtr size;
- public readonly uint mode;
- }
-
- /** Package filelist container */
- public struct _alpm_filelist_t
- {
- public UIntPtr count;
- private IntPtr files;
-
- /* FIXME: This is broken as shit */
- public alpm_file_t[] Unmarshal()
- {
- var iCount = (int) this.count;
- var byteCount = Marshal.SizeOf() * iCount;
- var byteBuffer = new byte[byteCount];
- Marshal.Copy(files, byteBuffer, 0, byteBuffer.Length);
- var result = new alpm_file_t[iCount];
-
- Buffer.BlockCopy(byteBuffer, 0, result, 0, byteBuffer.Length);
- return result;
- }
- }
-
- /** Local package or package file backup entry */
- public struct _alpm_backup_t
- {
- string name;
- string hash;
- }
-
- public class alpm_pgpkey_t
- {
- public byte[] data;
- public string fingerprint;
- public string uid;
- public string name;
- public string email;
- public long created;
- public long expires;
- public uint revoked;
- public char pubkey_algo;
- }
-
- public class PgpKeyInMarshaler : ICustomMarshaler
- {
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
- private class NativePgpKey
- {
- public IntPtr data;
- public string fingerprint;
- public string uid;
- public string name;
- public string email;
- public long created;
- public long expires;
- public uint length;
- public uint revoked;
- public char pubkey_algo;
- }
-
- public void CleanUpManagedData(object ManagedObj) { }
- public void CleanUpNativeData(IntPtr pNativeData) { }
-
- public int GetNativeDataSize()
- {
- throw new NotImplementedException();
- }
-
- public IntPtr MarshalManagedToNative(object ManagedObj)
- {
- throw new NotImplementedException();
- }
-
- public object MarshalNativeToManaged(IntPtr pNativeData)
- {
- var raw = Marshal.PtrToStructure(pNativeData);
- var managed = new alpm_pgpkey_t()
- {
- data = new byte[raw.length],
- fingerprint = raw.fingerprint,
- uid = raw.uid,
- name = raw.name,
- email = raw.email,
- created = raw.created,
- expires = raw.expires,
- revoked = raw.revoked,
- pubkey_algo = raw.pubkey_algo
- };
- Marshal.Copy(raw.data, managed.data, 0, (int) raw.length);
- return managed;
- }
- }
-
- /**
- * Signature result. Contains the key, status, and validity of a given
- * signature.
- */
- public readonly struct alpm_sigresult_t
- {
- [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PgpKeyInMarshaler))]
- readonly alpm_pgpkey_t key;
-
- readonly alpm_sigstatus_t status;
- readonly alpm_sigvalidity_t validity;
- }
-
- /**
- * Signature list. Contains the number of signatures found and a pointer to an
- * array of results. The array is of size count.
- */
- public class SigListInMarshaler : ICustomMarshaler
- {
- public void CleanUpManagedData(object ManagedObj) { }
- public void CleanUpNativeData(IntPtr pNativeData) { }
-
- public int GetNativeDataSize()
- {
- throw new NotImplementedException();
- }
-
- public IntPtr MarshalManagedToNative(object ManagedObj)
- {
- throw new NotImplementedException();
- }
-
- public object MarshalNativeToManaged(IntPtr pNativeData)
- {
- UIntPtr count;
- IntPtr data;
- unsafe
- {
- count = *(UIntPtr*) pNativeData;
- data = *(IntPtr*) (pNativeData + sizeof(UIntPtr));
- }
-
- var iCount = (int) count;
- var result = new alpm_sigresult_t[iCount];
- // NOTE: I expect this to fail cuz i didn't implement the above GetNativeDataSize
- for (var i = 0; i < iCount; ++i, data += Marshal.SizeOf())
- {
- result[i] = Marshal.PtrToStructure(data);
- }
-
- return result;
- }
- }
-/*
- * Hooks
- */
-
- enum alpm_hook_when_t
- {
- HOOK_PRE_TRANSACTION = 1,
- HOOK_POST_TRANSACTION
- }
-
-/*
- * Logging facilities
- */
-
- /** Logging Levels */
- enum _alpm_loglevel_t
- {
- LOG_ERROR = 1,
- LOG_WARNING = (1 << 1),
- LOG_DEBUG = (1 << 2),
- LOG_FUNCTION = (1 << 3)
- }
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct alpm_pkg_p
@@ -479,7 +64,7 @@ namespace nalpm
public Handle(string root, string dbpath)
{
- var err = errno_t.ERR_OK;
+ var err = ErrNo.ERR_OK;
_handle = alpm.alpm_initialize(root, dbpath, ref err);
if (_handle.IsInvalid)
{
@@ -700,8 +285,8 @@ namespace nalpm
{
public Exception() { }
public Exception(SafeAlpmHandle handle) : base(Alpm.StrError(alpm.alpm_errno(handle))) { }
- public Exception(errno_t errno) : base(Alpm.StrError(errno)) { }
- public Exception(errno_t errno, System.Exception inner) : base(Alpm.StrError(errno), inner) { }
+ public Exception(ErrNo errno) : base(Alpm.StrError(errno)) { }
+ public Exception(ErrNo errno, System.Exception inner) : base(Alpm.StrError(errno), inner) { }
protected Exception(SerializationInfo info,
StreamingContext context) : base(info, context) { }
@@ -826,7 +411,7 @@ namespace nalpm
public SigLevel SigLevel => alpm.alpm_db_get_siglevel(_db);
- public errno_t Valid => alpm.alpm_db_get_valid(_db) != 0 ? alpm.alpm_errno(_handle) : errno_t.ERR_OK;
+ public ErrNo Valid => alpm.alpm_db_get_valid(_db) != 0 ? alpm.alpm_errno(_handle) : ErrNo.ERR_OK;
public bool Update(bool force)
{
@@ -867,10 +452,10 @@ namespace nalpm
public static extern int alpm_option_remove_cachedir(SafeAlpmHandle handle, string cachedir);
[DllImport(nameof(alpm))]
- public static extern errno_t alpm_errno(SafeAlpmHandle handle);
+ public static extern ErrNo alpm_errno(SafeAlpmHandle handle);
[DllImport(nameof(alpm))]
- public static extern IntPtr alpm_strerror(errno_t err);
+ public static extern IntPtr alpm_strerror(ErrNo err);
[DllImport(nameof(alpm))]
public static extern IntPtr alpm_get_localdb(SafeAlpmHandle handle);
@@ -906,7 +491,7 @@ namespace nalpm
public static extern caps alpm_capabilities();
[DllImport(nameof(alpm), CharSet = CharSet.Ansi)]
- public static extern SafeAlpmHandle alpm_initialize(string root, string dbpath, ref errno_t err);
+ public static extern SafeAlpmHandle alpm_initialize(string root, string dbpath, ref ErrNo err);
[DllImport(nameof(alpm))]
public static extern int alpm_release(IntPtr handle);
@@ -941,12 +526,13 @@ namespace nalpm
internal static class Alpm
{
+
public static string Version()
{
return Marshal.PtrToStringUTF8(alpm.alpm_version());
}
- public static string StrError(errno_t err)
+ public static string StrError(ErrNo err)
{
return Marshal.PtrToStringUTF8(alpm.alpm_strerror(err));
}
diff --git a/CollectionWrapper`2.cs b/CollectionWrapper`2.cs
new file mode 100644
index 0000000..f3b5db8
--- /dev/null
+++ b/CollectionWrapper`2.cs
@@ -0,0 +1,79 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using Foodsoft.Alpm;
+
+namespace Foodsoft.Alpm
+{
+ internal struct CollectionWrapper : ICollection where TImpl : struct,
+ IAlpmItemsAccessor
+ {
+ private TImpl _impl;
+
+ public CollectionWrapper(TImpl impl)
+ {
+ _impl = impl;
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return (IEnumerator) GetEnumerator();
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ var result = new List();
+ var intPtr = _impl.GetItems();
+ unsafe
+ {
+ for (var list = (alpm_list_t*) intPtr; list != null; list = alpm.alpm_list_next(list))
+ {
+ result.Add(_impl.PtrToItem(list->data));
+ }
+ }
+
+ return result.GetEnumerator();
+ }
+
+
+ public void Add(TElement item)
+ {
+ _impl.AddItem(item);
+ }
+
+ public void Clear()
+ {
+ _impl.SetItems(IntPtr.Zero);
+ }
+
+
+ public bool Contains(TElement item) =>
+ _impl.FindItem(item) != IntPtr.Zero;
+
+ public void CopyTo(TElement[] array, int arrayIndex)
+ {
+ var intPtr = _impl.GetItems();
+ unsafe
+ {
+ for (var list = (alpm_list_t*) intPtr; list != null; list = alpm.alpm_list_next(list))
+ {
+ array[arrayIndex++] = _impl.PtrToItem(list->data);
+ }
+ }
+ }
+
+ public bool Remove(TElement item)
+ {
+ var err = _impl.RemoveItem(item);
+ if (err < 0)
+ {
+ throw new Exception(alpm.alpm_errno(_impl.SafeAlpmHandle));
+ }
+
+ return err == 0;
+ }
+
+ public int Count => (int) alpm.alpm_list_count(_impl.GetItems());
+ public bool IsReadOnly => false;
+ }
+}
\ No newline at end of file
diff --git a/Database.cs b/Database.cs
new file mode 100644
index 0000000..9b781fd
--- /dev/null
+++ b/Database.cs
@@ -0,0 +1,4 @@
+$HEADER$namespace $NAMESPACE$
+{
+ public class $CLASS$ {$END$}
+}
\ No newline at end of file
diff --git a/nalpm.csproj b/DotNetAlpm.csproj
similarity index 82%
rename from nalpm.csproj
rename to DotNetAlpm.csproj
index e76d8c2..71399ab 100644
--- a/nalpm.csproj
+++ b/DotNetAlpm.csproj
@@ -5,6 +5,7 @@
netcoreapp3.1
true
enable
+ nalpm
diff --git a/ErrNo.cs b/ErrNo.cs
new file mode 100644
index 0000000..22b9f06
--- /dev/null
+++ b/ErrNo.cs
@@ -0,0 +1,4 @@
+$HEADER$namespace $NAMESPACE$
+{
+ public enum $ENUM$ {$END$}
+}
\ No newline at end of file
diff --git a/Exception.cs b/Exception.cs
new file mode 100644
index 0000000..9b781fd
--- /dev/null
+++ b/Exception.cs
@@ -0,0 +1,4 @@
+$HEADER$namespace $NAMESPACE$
+{
+ public class $CLASS$ {$END$}
+}
\ No newline at end of file
diff --git a/Handle.cs b/Handle.cs
new file mode 100644
index 0000000..9b781fd
--- /dev/null
+++ b/Handle.cs
@@ -0,0 +1,4 @@
+$HEADER$namespace $NAMESPACE$
+{
+ public class $CLASS$ {$END$}
+}
\ No newline at end of file
diff --git a/IAlpmItemsAccessor`1.cs b/IAlpmItemsAccessor`1.cs
new file mode 100644
index 0000000..5b69a12
--- /dev/null
+++ b/IAlpmItemsAccessor`1.cs
@@ -0,0 +1,16 @@
+using System;
+
+namespace Foodsoft.Alpm
+{
+ internal interface IAlpmItemsAccessor
+ {
+ SafeAlpmHandle SafeAlpmHandle { get; }
+ public IntPtr GetItems();
+ public int SetItems(IntPtr list);
+ public int AddItem(TElement item);
+ public int RemoveItem(TElement item);
+ public IntPtr FindItem(TElement item);
+ public TElement PtrToItem(IntPtr p);
+ }
+
+}
\ No newline at end of file
diff --git a/IAlpmReadOnlyItemsAccessor`1.cs b/IAlpmReadOnlyItemsAccessor`1.cs
new file mode 100644
index 0000000..34a14a9
--- /dev/null
+++ b/IAlpmReadOnlyItemsAccessor`1.cs
@@ -0,0 +1,7 @@
+namespace Foodsoft.Alpm
+{
+ public class IAlpmReadOnlyItemsAccessor
+ {
+
+ }
+}
\ No newline at end of file
diff --git a/Junk.cs b/Junk.cs
new file mode 100644
index 0000000..0f48790
--- /dev/null
+++ b/Junk.cs
@@ -0,0 +1,7 @@
+namespace Alpm
+{
+ public class Junk
+ {
+
+ }
+}
\ No newline at end of file
diff --git a/ReadOnlyCollectionWrapper`2.cs b/ReadOnlyCollectionWrapper`2.cs
new file mode 100644
index 0000000..9b781fd
--- /dev/null
+++ b/ReadOnlyCollectionWrapper`2.cs
@@ -0,0 +1,4 @@
+$HEADER$namespace $NAMESPACE$
+{
+ public class $CLASS$ {$END$}
+}
\ No newline at end of file
diff --git a/SafeAlpmHandle.cs b/SafeAlpmHandle.cs
new file mode 100644
index 0000000..9b781fd
--- /dev/null
+++ b/SafeAlpmHandle.cs
@@ -0,0 +1,4 @@
+$HEADER$namespace $NAMESPACE$
+{
+ public class $CLASS$ {$END$}
+}
\ No newline at end of file
diff --git a/SafeDatabaseHandle.cs b/SafeDatabaseHandle.cs
new file mode 100644
index 0000000..9b781fd
--- /dev/null
+++ b/SafeDatabaseHandle.cs
@@ -0,0 +1,4 @@
+$HEADER$namespace $NAMESPACE$
+{
+ public class $CLASS$ {$END$}
+}
\ No newline at end of file
diff --git a/SafeListHandle.cs b/SafeListHandle.cs
new file mode 100644
index 0000000..c5ec06a
--- /dev/null
+++ b/SafeListHandle.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.ConstrainedExecution;
+
+namespace Foodsoft.Alpm
+{
+ internal struct ListRef : CriticalFinalIDisposable
+ {
+ public SafeAlpmHandle SafeAlpmHandle
+ {
+ [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
+ [PrePrepareMethod]
+ get;
+ }
+
+ [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail), PrePrepareMethod]
+ public ListRef(SafeAlpmHandle handle)
+ {
+ SafeAlpmHandle = null!;
+ RuntimeHelpers.PrepareConstrainedRegions();
+ try { }
+ finally
+ {
+ SafeAlpmHandle = handle;
+ var success = false;
+ handle.DangerousAddRef(ref success);
+ if (success)
+ SafeAlpmHandle = handle;
+ else
+ {
+ SafeAlpmHandle = null!;
+ throw new ObjectDisposedException(GetType().FullName);
+ }
+ }
+ }
+
+ ~ListRef()
+ {
+
+ }
+
+ public void Dispose()
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/UTF8InMarshaler.cs b/UTF8InMarshaler.cs
new file mode 100644
index 0000000..3653351
--- /dev/null
+++ b/UTF8InMarshaler.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace Foodsoft.Alpm
+{
+ internal readonly struct UTF8Marshaler : ICustomMarshaler
+ {
+ private static readonly UTF8Marshaler _instance = default;
+
+ // ReSharper disable once UnusedMember.Local
+ // ReSharper disable once UnusedParameter.Local
+ private static ICustomMarshaler GetInstance(string cookie)
+ {
+ return _instance;
+ }
+
+ public void CleanUpManagedData(object managedObj) { }
+
+ public void CleanUpNativeData(IntPtr pNativeData)
+ {
+ if (pNativeData == IntPtr.Zero)
+ return;
+ Marshal.FreeHGlobal(pNativeData);
+ }
+
+ public int GetNativeDataSize() => -1;
+
+ public unsafe IntPtr MarshalManagedToNative(object? managedObj)
+ {
+ if (managedObj is null) return IntPtr.Zero;
+
+ var s = (string) managedObj;
+
+ var nb = Encoding.UTF8.GetMaxByteCount(s.Length);
+
+ var pMem = Marshal.AllocHGlobal(nb + 1);
+ var pbMem = (byte*) pMem;
+
+ int nbWritten;
+ fixed (char* firstChar = s)
+ {
+ nbWritten = Encoding.UTF8.GetBytes(firstChar, s.Length, pbMem, nb);
+ }
+ pbMem[nbWritten] = 0;
+ return pMem;
+ }
+
+ public object MarshalNativeToManaged(IntPtr pNativeData)
+ {
+ return Marshal.PtrToStringUTF8(pNativeData)!;
+ }
+ }
+}
\ No newline at end of file
diff --git a/UTF8OutMarshaler.cs b/UTF8OutMarshaler.cs
new file mode 100644
index 0000000..9b781fd
--- /dev/null
+++ b/UTF8OutMarshaler.cs
@@ -0,0 +1,4 @@
+$HEADER$namespace $NAMESPACE$
+{
+ public class $CLASS$ {$END$}
+}
\ No newline at end of file
diff --git a/Wrapper.cs b/Wrapper.cs
new file mode 100644
index 0000000..b5d91dc
--- /dev/null
+++ b/Wrapper.cs
@@ -0,0 +1,7 @@
+namespace Foodsoft.Alpm
+{
+ public class Wrapper
+ {
+
+ }
+}
\ No newline at end of file
diff --git a/alpm.cs b/alpm.cs
new file mode 100644
index 0000000..adfa77b
--- /dev/null
+++ b/alpm.cs
@@ -0,0 +1,7 @@
+namespace Alpm
+{
+ public class alpm
+ {
+
+ }
+}
\ No newline at end of file