Skip to content

Commit 72a4536

Browse files
authored
Feature/multirar (#43)
* Implementation of multi-volume archive support, RAR test case
1 parent 7fbcb2c commit 72a4536

11 files changed

+114
-35
lines changed

CHANGELOG.md

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
v0.1.4 - Jun 28 2023
2+
3+
- Add support for multi-volume archives
4+
5+
v0.1.3 - Dec 23 2022
6+
7+
- Add optional argument to LibArchiveReader to configure blocksize, default 1MiB
8+
9+
v0.1.2 - Oct 27 2022
10+
11+
- Fix memory leak on Linux in musl-libc malloc
12+
13+
v0.1.1 - Sep 22 2022
14+
15+
- First full release, supporting Linux, Windows and MacOS x64 plus MacOS ARM64

LibArchive.Net/LibArchiveReader.cs

+45-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.IO;
4+
using System.Linq;
45
using System.Runtime.InteropServices;
56
using Microsoft.Win32.SafeHandles;
67

@@ -52,7 +53,20 @@ public LibArchiveReader(string filename,uint blockSize = 1<<20) : base(true)
5253
archive_read_support_filter_all(handle);
5354
archive_read_support_format_all(handle);
5455
if (archive_read_open_filename(handle, uName.Ptr, (int)blockSize) != 0)
55-
throw new ApplicationException("TODO: Archive open failed");
56+
Throw();
57+
}
58+
59+
/// <summary>
60+
///
61+
/// </summary>
62+
public LibArchiveReader(string[] filenames,uint blockSize=1<<20) : base(true)
63+
{
64+
using var names = new DisposableStringArray(filenames);
65+
handle = archive_read_new();
66+
archive_read_support_filter_all(handle);
67+
archive_read_support_format_all(handle);
68+
if (archive_read_open_filenames(handle, names.Ptr, (int)blockSize) != 0)
69+
Throw();
5670
}
5771

5872
private void Throw()
@@ -147,6 +161,9 @@ public override long Position
147161
[DllImport("archive")]
148162
private static extern int archive_read_open_filename(IntPtr a, IntPtr filename, int blocksize);
149163

164+
[DllImport("archive")]
165+
private static extern int archive_read_open_filenames(IntPtr a, IntPtr filename, int blocksize);
166+
150167
[DllImport("archive")]
151168
private static extern int archive_read_data(IntPtr a, ref byte buff, int size);
152169

@@ -162,3 +179,30 @@ public override long Position
162179
[DllImport("archive")]
163180
private static extern IntPtr archive_error_string(IntPtr a);
164181
}
182+
183+
public class DisposableStringArray : IDisposable
184+
{
185+
private readonly IntPtr[] backing;
186+
private readonly GCHandle handle;
187+
private readonly SafeStringBuffer[] strings;
188+
189+
public DisposableStringArray(string[] a)
190+
{
191+
backing = new IntPtr[a.Length+1];
192+
strings = a.Select(s => new SafeStringBuffer(s)).ToArray();
193+
for (int i=0;i<strings.Length;i++)
194+
backing[i] = strings[i].Ptr;
195+
backing[strings.Length] = IntPtr.Zero;
196+
handle = GCHandle.Alloc(backing, GCHandleType.Pinned);
197+
}
198+
199+
public IntPtr Ptr => handle.AddrOfPinnedObject();
200+
201+
public void Dispose()
202+
{
203+
GC.SuppressFinalize(this);
204+
handle.Free();
205+
foreach (var s in strings)
206+
s.Dispose();
207+
}
208+
}

LibArchive.Net/SafeStringBuffer.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public class SafeStringBuffer : SafeHandleZeroOrMinusOneIsInvalid
1111
public SafeStringBuffer(string s) : base(true)
1212
{
1313
if (s is null)
14-
throw new ArgumentException(nameof(s));
14+
throw new ArgumentNullException(nameof(s));
1515
handle = Marshal.StringToCoTaskMemUTF8(s);
1616
}
1717

Test.LibArchive.Net/7zTests.cs

-32
This file was deleted.

Test.LibArchive.Net/ReaderTests.cs

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using System.Security.Cryptography;
2+
using System.Text;
3+
using LibArchive.Net;
4+
using NUnit.Framework;
5+
6+
namespace Test.LibArchive.Net;
7+
8+
public class SevenZipTests
9+
{
10+
private readonly SHA256 hash = SHA256.Create();
11+
12+
[Test]
13+
public void Test7z()
14+
{
15+
using var lar = new LibArchiveReader("7ztest.7z");
16+
foreach (var e in lar.Entries())
17+
{
18+
using var s = e.Stream;
19+
StringBuilder sb = new(e.Name,e.Name.Length+33);
20+
sb.Append(' ');
21+
foreach (var d in hash.ComputeHash(s))
22+
{
23+
sb.Append(d.ToString("x2"));
24+
}
25+
Console.WriteLine(sb);
26+
}
27+
Assert.Pass();
28+
}
29+
30+
[Test]
31+
public void TestMultiRar()
32+
{
33+
var files = Directory.GetFiles(TestContext.CurrentContext.TestDirectory, "rartest*.rar");
34+
Array.Sort(files);
35+
Assert.That(files, Has.Length.EqualTo(4), "Expected 4 RAR segments");
36+
using var rar = new LibArchiveReader(files);
37+
foreach (var e in rar.Entries())
38+
{
39+
using var s = e.Stream;
40+
StringBuilder sb = new(e.Name, e.Name.Length + 33);
41+
sb.Append(' ');
42+
foreach (var d in hash.ComputeHash(s))
43+
{
44+
sb.Append(d.ToString("x2"));
45+
}
46+
Console.WriteLine(sb);
47+
}
48+
}
49+
}

Test.LibArchive.Net/Test.LibArchive.Net.csproj

+4
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,9 @@
1717
</ItemGroup>
1818
<ItemGroup>
1919
<None Update="7ztest.7z" CopyToOutputDirectory="PreserveNewest" />
20+
<None Update="rartest.part00001.rar" CopyToOutputDirectory="PreserveNewest" />
21+
<None Update="rartest.part00002.rar" CopyToOutputDirectory="PreserveNewest" />
22+
<None Update="rartest.part00003.rar" CopyToOutputDirectory="PreserveNewest" />
23+
<None Update="rartest.part00004.rar" CopyToOutputDirectory="PreserveNewest" />
2024
</ItemGroup>
2125
</Project>

Test.LibArchive.Net/Usings.cs

-1
This file was deleted.
16 KB
Binary file not shown.
16 KB
Binary file not shown.
16 KB
Binary file not shown.
8.12 KB
Binary file not shown.

0 commit comments

Comments
 (0)