7Zip and Rar

This commit is contained in:
Adam Hathcock
2026-06-15 09:29:50 +01:00
parent 2866bfbd54
commit e9e05520d6
4 changed files with 146 additions and 10 deletions

View File

@@ -71,22 +71,19 @@ public partial class RarArchiveEntry : RarEntry, IArchiveEntry
public Stream OpenEntryStream()
{
var readStream = new MultiVolumeReadOnlyStream(Parts.Cast<RarFilePart>());
RarStream stream;
if (IsRarV3)
{
stream = new RarStream(
archive.UnpackV1.Value,
FileHeader,
new MultiVolumeReadOnlyStream(Parts.Cast<RarFilePart>())
);
stream = RarCrcStream.Create(archive.UnpackV1.Value, FileHeader, readStream);
}
else if (FileHeader.FileCrc?.Length > 5)
{
stream = RarBLAKE2spStream.Create(archive.UnpackV2017.Value, FileHeader, readStream);
}
else
{
stream = new RarStream(
archive.UnpackV2017.Value,
FileHeader,
new MultiVolumeReadOnlyStream(Parts.Cast<RarFilePart>())
);
stream = RarCrcStream.Create(archive.UnpackV2017.Value, FileHeader, readStream);
}
stream.Initialize();

View File

@@ -18,6 +18,28 @@ public class SevenZipEntry : Entry
public override long Crc => FilePart.Header.Crc ?? 0;
internal override ChecksumDescriptor Checksum
{
get
{
if (
IsDirectory
|| FilePart.Header.IsAnti
|| !FilePart.Header.HasStream
|| !FilePart.Header.Crc.HasValue
)
{
return default;
}
return new ChecksumDescriptor(
ChecksumKind.Crc32,
FilePart.Header.Crc.Value,
IsAvailable: true
);
}
}
public override string? Key => FilePart.Header.Name;
public override string? LinkTarget => null;

View File

@@ -0,0 +1,36 @@
using System.IO;
using System.Linq;
using SharpCompress.Archives;
using SharpCompress.Archives.Rar;
using SharpCompress.Common;
using Xunit;
namespace SharpCompress.Test.Rar;
public class RarCrcExtractionTests : ArchiveTests
{
[Theory]
[InlineData("Rar.rar")]
[InlineData("Rar5.rar")]
public void Rar_Archive_WriteToFile_Throws_On_Crc_Mismatch(string archiveName)
{
using var archive = RarArchive.OpenArchive(Path.Combine(TEST_ARCHIVES_PATH, archiveName));
var entry = CorruptFirstFileCrc(archive);
var destination = Path.Combine(SCRATCH_FILES_PATH, $"{archiveName}-crc-mismatch.txt");
Assert.Throws<InvalidFormatException>(() => entry.WriteToFile(destination));
}
private static RarArchiveEntry CorruptFirstFileCrc(IArchive archive)
{
var entry = archive.Entries.OfType<RarArchiveEntry>().First(e => !e.IsDirectory);
CorruptCrc(entry);
return entry;
}
private static void CorruptCrc(RarArchiveEntry entry)
{
var crc = entry.FileHeader.FileCrc.NotNull();
crc[0] ^= 0xFF;
}
}

View File

@@ -0,0 +1,81 @@
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using SharpCompress.Archives;
using SharpCompress.Archives.SevenZip;
using SharpCompress.Common;
using SharpCompress.Common.SevenZip;
using Xunit;
namespace SharpCompress.Test.SevenZip;
public class SevenZipCrcExtractionTests : ArchiveTests
{
[Fact]
public void SevenZip_Archive_WriteToFile_Throws_On_Crc_Mismatch()
{
using var archive = SevenZipArchive.OpenArchive(
Path.Combine(TEST_ARCHIVES_PATH, "7Zip.LZMA.7z")
);
var entry = CorruptFirstFileCrc(archive);
var destination = Path.Combine(SCRATCH_FILES_PATH, "7zip-crc-mismatch.txt");
var exception = Assert.Throws<InvalidFormatException>(() => entry.WriteToFile(destination));
Assert.Contains(entry.Key!, exception.Message);
}
[Fact]
public void SevenZip_Archive_WriteToFile_Skips_Crc_Mismatch_When_Disabled()
{
using var archive = SevenZipArchive.OpenArchive(
Path.Combine(TEST_ARCHIVES_PATH, "7Zip.LZMA.7z")
);
var entry = CorruptFirstFileCrc(archive);
var destination = Path.Combine(SCRATCH_FILES_PATH, "7zip-crc-disabled.txt");
entry.WriteToFile(destination, new ExtractionOptions { CheckCrc = false });
Assert.True(new FileInfo(destination).Length > 0);
}
[Fact]
public async Task SevenZip_Archive_WriteToFileAsync_Throws_On_Crc_Mismatch()
{
await using var archive = await SevenZipArchive.OpenAsyncArchive(
Path.Combine(TEST_ARCHIVES_PATH, "7Zip.LZMA.7z")
);
var entries = await archive.EntriesAsync.ToListAsync();
var entry = CorruptFirstFileCrc(entries);
var destination = Path.Combine(SCRATCH_FILES_PATH, "7zip-crc-mismatch-async.txt");
var exception = await Assert.ThrowsAsync<InvalidFormatException>(async () =>
await entry.WriteToFileAsync(destination)
);
Assert.Contains(entry.Key!, exception.Message);
}
private static IArchiveEntry CorruptFirstFileCrc(IArchive archive)
{
var entry = archive.Entries.First(e => !e.IsDirectory);
CorruptCrc(entry);
return entry;
}
private static IArchiveEntry CorruptFirstFileCrc(
System.Collections.Generic.IEnumerable<IArchiveEntry> entries
)
{
var entry = entries.First(e => !e.IsDirectory);
CorruptCrc(entry);
return entry;
}
private static void CorruptCrc(IArchiveEntry entry)
{
var sevenZipEntry = Assert.IsAssignableFrom<SevenZipEntry>(entry);
var crc = sevenZipEntry.FilePart.Header.Crc.NotNull();
sevenZipEntry.FilePart.Header.Crc = crc ^ 0xFFFFFFFF;
}
}