From 72a4536b8350c44b0761af88949d31059e64f10d Mon Sep 17 00:00:00 2001 From: James A Sutherland Date: Thu, 29 Jun 2023 09:54:44 -0500 Subject: [PATCH] Feature/multirar (#43) * Implementation of multi-volume archive support, RAR test case --- CHANGELOG.md | 15 ++++++ LibArchive.Net/LibArchiveReader.cs | 46 +++++++++++++++- LibArchive.Net/SafeStringBuffer.cs | 2 +- Test.LibArchive.Net/7zTests.cs | 32 ------------ Test.LibArchive.Net/ReaderTests.cs | 49 ++++++++++++++++++ .../Test.LibArchive.Net.csproj | 4 ++ Test.LibArchive.Net/Usings.cs | 1 - Test.LibArchive.Net/rartest.part00001.rar | Bin 0 -> 16384 bytes Test.LibArchive.Net/rartest.part00002.rar | Bin 0 -> 16384 bytes Test.LibArchive.Net/rartest.part00003.rar | Bin 0 -> 16384 bytes Test.LibArchive.Net/rartest.part00004.rar | Bin 0 -> 8311 bytes 11 files changed, 114 insertions(+), 35 deletions(-) create mode 100644 CHANGELOG.md delete mode 100644 Test.LibArchive.Net/7zTests.cs create mode 100644 Test.LibArchive.Net/ReaderTests.cs delete mode 100644 Test.LibArchive.Net/Usings.cs create mode 100644 Test.LibArchive.Net/rartest.part00001.rar create mode 100644 Test.LibArchive.Net/rartest.part00002.rar create mode 100644 Test.LibArchive.Net/rartest.part00003.rar create mode 100644 Test.LibArchive.Net/rartest.part00004.rar diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..69f38ce --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,15 @@ +v0.1.4 - Jun 28 2023 + +- Add support for multi-volume archives + +v0.1.3 - Dec 23 2022 + +- Add optional argument to LibArchiveReader to configure blocksize, default 1MiB + +v0.1.2 - Oct 27 2022 + +- Fix memory leak on Linux in musl-libc malloc + +v0.1.1 - Sep 22 2022 + +- First full release, supporting Linux, Windows and MacOS x64 plus MacOS ARM64 diff --git a/LibArchive.Net/LibArchiveReader.cs b/LibArchive.Net/LibArchiveReader.cs index 99c40e4..fd628cb 100644 --- a/LibArchive.Net/LibArchiveReader.cs +++ b/LibArchive.Net/LibArchiveReader.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles; @@ -52,7 +53,20 @@ public LibArchiveReader(string filename,uint blockSize = 1<<20) : base(true) archive_read_support_filter_all(handle); archive_read_support_format_all(handle); if (archive_read_open_filename(handle, uName.Ptr, (int)blockSize) != 0) - throw new ApplicationException("TODO: Archive open failed"); + Throw(); + } + + /// + /// + /// + public LibArchiveReader(string[] filenames,uint blockSize=1<<20) : base(true) + { + using var names = new DisposableStringArray(filenames); + handle = archive_read_new(); + archive_read_support_filter_all(handle); + archive_read_support_format_all(handle); + if (archive_read_open_filenames(handle, names.Ptr, (int)blockSize) != 0) + Throw(); } private void Throw() @@ -147,6 +161,9 @@ public override long Position [DllImport("archive")] private static extern int archive_read_open_filename(IntPtr a, IntPtr filename, int blocksize); + [DllImport("archive")] + private static extern int archive_read_open_filenames(IntPtr a, IntPtr filename, int blocksize); + [DllImport("archive")] private static extern int archive_read_data(IntPtr a, ref byte buff, int size); @@ -162,3 +179,30 @@ public override long Position [DllImport("archive")] private static extern IntPtr archive_error_string(IntPtr a); } + +public class DisposableStringArray : IDisposable +{ + private readonly IntPtr[] backing; + private readonly GCHandle handle; + private readonly SafeStringBuffer[] strings; + + public DisposableStringArray(string[] a) + { + backing = new IntPtr[a.Length+1]; + strings = a.Select(s => new SafeStringBuffer(s)).ToArray(); + for (int i=0;i handle.AddrOfPinnedObject(); + + public void Dispose() + { + GC.SuppressFinalize(this); + handle.Free(); + foreach (var s in strings) + s.Dispose(); + } +} \ No newline at end of file diff --git a/LibArchive.Net/SafeStringBuffer.cs b/LibArchive.Net/SafeStringBuffer.cs index a2511a3..55b76dd 100644 --- a/LibArchive.Net/SafeStringBuffer.cs +++ b/LibArchive.Net/SafeStringBuffer.cs @@ -11,7 +11,7 @@ public class SafeStringBuffer : SafeHandleZeroOrMinusOneIsInvalid public SafeStringBuffer(string s) : base(true) { if (s is null) - throw new ArgumentException(nameof(s)); + throw new ArgumentNullException(nameof(s)); handle = Marshal.StringToCoTaskMemUTF8(s); } diff --git a/Test.LibArchive.Net/7zTests.cs b/Test.LibArchive.Net/7zTests.cs deleted file mode 100644 index 5cb7a0f..0000000 --- a/Test.LibArchive.Net/7zTests.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Security.Cryptography; -using System.Text; -using LibArchive.Net; - -namespace Test.LibArchive.Net; - -public class SevenZipTests -{ - [SetUp] - public void Setup() - { - } - - [Test] - public void Test1() - { - var hash=SHA256.Create(); - using var lar = new LibArchiveReader("7ztest.7z"); - foreach (var e in lar.Entries()) - { - Console.WriteLine(e.Name); - using var s = e.Stream; - StringBuilder sb = new(); - foreach (var d in hash.ComputeHash(s)) - { - sb.Append(d.ToString("x2")); - } - Console.WriteLine(sb); - } - Assert.Pass(); - } -} \ No newline at end of file diff --git a/Test.LibArchive.Net/ReaderTests.cs b/Test.LibArchive.Net/ReaderTests.cs new file mode 100644 index 0000000..24745cc --- /dev/null +++ b/Test.LibArchive.Net/ReaderTests.cs @@ -0,0 +1,49 @@ +using System.Security.Cryptography; +using System.Text; +using LibArchive.Net; +using NUnit.Framework; + +namespace Test.LibArchive.Net; + +public class SevenZipTests +{ + private readonly SHA256 hash = SHA256.Create(); + + [Test] + public void Test7z() + { + using var lar = new LibArchiveReader("7ztest.7z"); + foreach (var e in lar.Entries()) + { + using var s = e.Stream; + StringBuilder sb = new(e.Name,e.Name.Length+33); + sb.Append(' '); + foreach (var d in hash.ComputeHash(s)) + { + sb.Append(d.ToString("x2")); + } + Console.WriteLine(sb); + } + Assert.Pass(); + } + + [Test] + public void TestMultiRar() + { + var files = Directory.GetFiles(TestContext.CurrentContext.TestDirectory, "rartest*.rar"); + Array.Sort(files); + Assert.That(files, Has.Length.EqualTo(4), "Expected 4 RAR segments"); + using var rar = new LibArchiveReader(files); + foreach (var e in rar.Entries()) + { + using var s = e.Stream; + StringBuilder sb = new(e.Name, e.Name.Length + 33); + sb.Append(' '); + foreach (var d in hash.ComputeHash(s)) + { + sb.Append(d.ToString("x2")); + } + Console.WriteLine(sb); + } + } +} \ No newline at end of file diff --git a/Test.LibArchive.Net/Test.LibArchive.Net.csproj b/Test.LibArchive.Net/Test.LibArchive.Net.csproj index 08b6a92..9cf4fb1 100644 --- a/Test.LibArchive.Net/Test.LibArchive.Net.csproj +++ b/Test.LibArchive.Net/Test.LibArchive.Net.csproj @@ -17,5 +17,9 @@ + + + + diff --git a/Test.LibArchive.Net/Usings.cs b/Test.LibArchive.Net/Usings.cs deleted file mode 100644 index cefced4..0000000 --- a/Test.LibArchive.Net/Usings.cs +++ /dev/null @@ -1 +0,0 @@ -global using NUnit.Framework; \ No newline at end of file diff --git a/Test.LibArchive.Net/rartest.part00001.rar b/Test.LibArchive.Net/rartest.part00001.rar new file mode 100644 index 0000000000000000000000000000000000000000..f12b4899c03826eefa3074dacffc37b1a98d8654 GIT binary patch literal 16384 zcmeI3ze>YU6vod@`Uh-l1wp|Nv?&_#R! z!9~$QaA|SW2e5+Bc6Etc)tbbU_6Z7=F5e~O4B=$BxjDb{-7i^Q*8&4>LAmSuqaNY( z3Xc$%mTU}421ZXt6xAciA!(R+$Ow7&4mLL9S}3-Y*iUw;3SH!X-k(ZhWuf#iru2HQ zOgotz_W798^4VZq&XOyq)9EQq; z3Ww=JrpO_awj>ABu=p&Dy2(MU*M2#;YkD)Sj5JJ%#x%V98j`fV zy_H}w@iZ7+OJsDeI$3J1_b%O*M6-wGgVIsl25$4A^K$=eyoi`%|DjX(=KDI$-}*b9 z3Z7f62780o;Sa+>>bs{iL8ecd_yBVyp(ML2IHUrZu58(QN<^;o*PdA!&>>Mj9iH s{mKMgy>5KY+USjl9!@04?JPW=)mNoj$^Q8N{MvSI*@h9L&*FOw0ZTS!z5oCK literal 0 HcmV?d00001 diff --git a/Test.LibArchive.Net/rartest.part00003.rar b/Test.LibArchive.Net/rartest.part00003.rar new file mode 100644 index 0000000000000000000000000000000000000000..aad0068c6b182968ad90e14e976361524ade6e1b GIT binary patch literal 16384 zcmeI3F-SsD7={0PpHCqxXz7711=19RP-{pKj%ITR4bh+=IM(1DoQj}1XlrUI8Y3uL z9a}0wa2299398%wYH*)7B;se&$?Qq?EOKj-%eb*rt%=eq|ZB4zLOY4-ewF5#$HuyUr4(K6t0EhtbZy?Iy`u>Dn>@=#ED@UDoTop!A2L@YB$RJmd zBnZ|35g-CYj@EEQIHKV@BGMSVg}3k)-ojgWJAB^K6w(yZ6e@2iiYSV74A8@VJtU2h z#zp%k-Ff6^1u~~C z65Zg+z-E|Um0Fa~#mv;;bo%Cav^O@|0VS^AK3Xh|7E5$1mPQlXXkr^pY@==G(Y7jcQOR(40w?2t`G1Em+SPvO&13LUVPfWP;9zOsP&m=1xw^rDfx|GnC^0W3KNmC) zr@;CJG!J)wF8{iF6YTfDSCZK@V+DJj+vBs&y{(TUj7?sh&wi4lZ@%qk#<%MF4IM(= z=3nRhWob0`ZP<0?Y?dNh+m@p2Yd?RKUr?@!Jkw~o;@-z8mv;zF`#e8CFQaH?>aMQW zmyV~bv3l53nZLMUmfob0t3Joqw}z=7S*H46iTtltKhEsb$D+4CH`vzQU_L7l#-`SB za_-5lX_*XLH!umYZqR#o%RaC2=ak-3!R^lqhnV#@xPzh`k?3Ov9&g-`iO zc(8ApIcvcS!`WRkH~M!6v_3p`Pj{l!)>l^fR$p|Z%vRMtX!4w>q5jV{datwp$3Knl zW8Y{@_*Ndh%QvTP?^EFkpSSqfUF3BVnEGmJ?l-nj<{A4Lk25~u{gSv& zylRS(o|Ct4W4!F{x4YHu&E)xqSNWJ+t-Cj`Q|_nl zYne;IzDFMI*#08=+UJBbAT&4qRyy(3ACW12pS2!n z+XiI3v~W>W-TXq*{=&j+dV;k%WCr=Kt3DwlDa9m3HS-5{eh?zpR!1TX^Mu)tfznYio|R{#31> z^#5FE<$=9#_pP9xj~sb(rQrMO-Emw#vP}moraR<&)lGkMW9o!!JmGnN zL*6XA_^PweMdx=k7YGwYrcs_*)C{jQz&+d