diff --git a/wrappers/cs/Common.cs b/wrappers/cs/Common.cs new file mode 100644 index 0000000..a3adaaf --- /dev/null +++ b/wrappers/cs/Common.cs @@ -0,0 +1,25 @@ +using System; +using System.Runtime.InteropServices; + +namespace Pack +{ + public static class Common + { + public const string LibraryPath = "pack"; + [DllImport(LibraryPath)] private static extern void getPackLibraryVersion(ref byte majorVersion, ref byte minorVersion, ref byte patchVersion); + [DllImport(LibraryPath)] private static extern byte readPackHeader(string filePath, ref PackHeader header); + + public static void GetPackLibraryVersion(ref byte majorVersion, ref byte minorVersion, ref byte patchVersion) + { + getPackLibraryVersion(ref majorVersion, ref minorVersion, ref patchVersion); + } + public static PackResult GetPackInfo(in string filePath, out PackHeader header) + { + + if (string.IsNullOrEmpty(filePath)) + throw new ArgumentNullException(nameof(filePath)); + header = new(); + return (PackResult)readPackHeader(filePath, ref header); + } + } +} diff --git a/wrappers/cs/PackHeader.cs b/wrappers/cs/PackHeader.cs new file mode 100644 index 0000000..4cce394 --- /dev/null +++ b/wrappers/cs/PackHeader.cs @@ -0,0 +1,15 @@ +using System.Runtime.InteropServices; + +namespace Pack +{ + [StructLayout(LayoutKind.Sequential)] + public struct PackHeader + { + public uint magic; + public byte versionMajor; + public byte versionMinor; + public byte versionPatch; + public byte isBigEndian; + public ulong itemCount; + } +} diff --git a/wrappers/cs/PackItemHeader.cs b/wrappers/cs/PackItemHeader.cs new file mode 100644 index 0000000..c82ca95 --- /dev/null +++ b/wrappers/cs/PackItemHeader.cs @@ -0,0 +1,14 @@ +using System.Runtime.InteropServices; + +namespace Pack +{ + [StructLayout(LayoutKind.Sequential)] + public struct PackItemHeader + { + public uint zipState; + public uint dataSize; + public byte pathSize; + public byte isReference; + public ulong dataOffset; + } +} diff --git a/wrappers/cs/PackReader.cs b/wrappers/cs/PackReader.cs new file mode 100644 index 0000000..30e9b60 --- /dev/null +++ b/wrappers/cs/PackReader.cs @@ -0,0 +1,115 @@ +using System; +using System.Runtime.InteropServices; + +namespace Pack +{ + public class PackReader + { + const CallingConvention conversion = CallingConvention.Cdecl; + [DllImport(Common.LibraryPath, CallingConvention = conversion)] protected static extern byte createFilePackReader(string filePath, bool isResourcesDirectory, uint threadCount, ref IntPtr packReader); + [DllImport(Common.LibraryPath, CallingConvention = conversion)] protected static extern void destroyPackReader(IntPtr packReader); + [DllImport(Common.LibraryPath, CallingConvention = conversion)] protected static extern ulong getPackItemCount(IntPtr packReader); + [DllImport(Common.LibraryPath, CallingConvention = conversion)] protected static extern bool getPackItemIndex(IntPtr packReader, string path, ref ulong index); + [DllImport(Common.LibraryPath, CallingConvention = conversion)] protected static extern uint getPackItemDataSize(IntPtr packReader, ulong index); + [DllImport(Common.LibraryPath, CallingConvention = conversion)] protected static extern uint getPackItemZipSize(IntPtr packReader, ulong index); + [DllImport(Common.LibraryPath, CallingConvention = conversion)] protected static extern ulong getPackItemFileOffset(IntPtr packReader, ulong index); + [DllImport(Common.LibraryPath, CallingConvention = conversion)] protected static extern bool isPackItemReference(IntPtr packReader, ulong index); + + [DllImport(Common.LibraryPath, CallingConvention = conversion)] protected static extern IntPtr getPackItemPath(IntPtr packReader, ulong index); + [DllImport(Common.LibraryPath, CallingConvention = conversion)] protected static extern PackResult readPackItemData(IntPtr packReader, ulong index, byte[] data, uint threadIndex); + [DllImport(Common.LibraryPath, CallingConvention = conversion)] protected static extern PackResult unpackFiles(string filePath, bool printProgress); + + protected IntPtr Handle; + + public ulong ItemCount => getPackItemCount(Handle); + + public PackReader(string filePath, bool isResourceDirectory = false, uint threadCount = 1) + { + var handle = IntPtr.Zero; + var result = createFilePackReader(filePath, isResourceDirectory, threadCount, ref handle); + + if (result != 0) + throw new Exception(result.ToString()); + + Handle = handle; + } + ~PackReader() + { + destroyPackReader(Handle); + } + + public bool GetItemIndex(in string path, ref ulong index) + { + if (string.IsNullOrEmpty(path)) + throw new ArgumentNullException(nameof(path)); + if (path.Length > byte.MaxValue) + throw new ArgumentOutOfRangeException(nameof(path)); + return getPackItemIndex(Handle, path, ref index); + } + public uint GetItemDataSize(in ulong index) + { + if (index >= ItemCount) + throw new ArgumentOutOfRangeException(nameof(index)); + return getPackItemDataSize(Handle, index); + } + public string GetItemPath(in ulong index) + { + if (index >= ItemCount) + throw new ArgumentOutOfRangeException(nameof(index)); + + var path = getPackItemPath(Handle, index); + return Marshal.PtrToStringAnsi(path); + } + + public PackResult ReadItemData(in string path, ref byte[] data, in uint thread = 0) + { + if (string.IsNullOrEmpty(path)) + throw new ArgumentNullException(nameof(path)); + if (path.Length > byte.MaxValue) + throw new ArgumentOutOfRangeException(nameof(path)); + + ulong index = 0; + if (getPackItemIndex(Handle, path, ref index)) + { + return ReadItemData(index, ref data, thread); + } + return PackResult.FailedToGetItem; + + } + + public PackResult ReadItemData(in ulong index, ref byte[] data, in uint thread = 0) + { + var result = readPackItemData(Handle, index, data, thread); + if (result != PackResult.Success) + return result; + return PackResult.Success; + } + + public byte[]? ReadItemData(in ulong index, in uint thread = 0) + { + uint size = getPackItemDataSize(Handle, index); + byte[] data = new byte[size]; + ReadItemData(index, ref data, thread); + return data; + } + public byte[]? ReadItemData(in string path, in uint thread = 0) + { + ulong index = 0; + if (getPackItemIndex(Handle, path, ref index)) + { + uint size = getPackItemDataSize(Handle, index); + byte[] data = new byte[size]; + ReadItemData(index, ref data, thread); + return data; + } + return null; + + } + public static PackResult UnpackFiles(in string filePath, in bool printProgress) + { + if (string.IsNullOrEmpty(filePath)) + throw new ArgumentNullException(nameof(filePath)); + return unpackFiles(filePath, printProgress); + } + } +} diff --git a/wrappers/cs/PackResult.cs b/wrappers/cs/PackResult.cs new file mode 100644 index 0000000..ab225d5 --- /dev/null +++ b/wrappers/cs/PackResult.cs @@ -0,0 +1,22 @@ +namespace Pack +{ + public enum PackResult + { + Success = 0, + FailedToAllocate = 1, + FailedToCreateZSTD = 2, + FailedToCreateFile = 3, + FailedToOpenFile = 4, + FailedToWriteFile = 5, + FailedToReadFile = 6, + FailedToSeekFile = 7, + FailedToGetDirectory = 8, + FailedToDecompress = 9, + FailedToGetItem = 10, + BadDataSize = 11, + BadFileType = 12, + BadFileVersion = 13, + BadFileEndianness = 14, + PackResultCount = 15 + } +} diff --git a/wrappers/cs/PackWriter.cs b/wrappers/cs/PackWriter.cs new file mode 100644 index 0000000..c46cff1 --- /dev/null +++ b/wrappers/cs/PackWriter.cs @@ -0,0 +1,22 @@ +using System; +using System.Runtime.InteropServices; + +namespace Pack +{ + public static class PackWriter + { + [DllImport(Common.LibraryPath, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] private static extern PackResult packFiles(string packPath, ulong fileCount, string[] filePaths, float zipThreshold, bool printProgress, OnPackFile callback); + + public delegate void OnPackFile(UInt64 index, object o); + public static PackResult PackFiles(in string packPath, in string[] filePaths, in float zipTreshold, in bool printProgress, OnPackFile callback) + { + if (string.IsNullOrEmpty(packPath)) + throw new ArgumentNullException(nameof(packPath)); + if (filePaths.Length == 0) + throw new ArgumentNullException(nameof(filePaths)); + + var res = packFiles(packPath, (ulong)filePaths.Length / 2, filePaths, zipTreshold, printProgress, callback); + return res; + } + } +}