Report the codec, not 7zAES, as an encrypted 7z entry's CompressionType

7-Zip writes 7zAES as the first coder of an encrypted folder, in front
of the codec. SevenZipFilePart.GetCompression() looked at the first
coder only, so CompressionType threw InvalidFormatException for every
entry of a 7-Zip-made encrypted archive. Skip the AES filter and report
the first real coder.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jay Sanati
2026-10-23 22:36:26 -07:00
parent e65e437c3d
commit a7d3b100a0
2 changed files with 28 additions and 1 deletions

View File

@@ -119,7 +119,11 @@ internal class SevenZipFilePart : FilePart
return CompressionType.None;
}
var coder = Folder.NotNull()._coders.First();
// 7zAES is a filter in front of the codec (7-Zip writes it as coder 0), so it says
// nothing about the compression; report the first real coder instead.
var coder =
Folder.NotNull()._coders.FirstOrDefault(c => c._methodId._id != CMethodId.K_AES_ID)
?? throw new InvalidFormatException();
return coder._methodId._id switch
{
K_COPY => CompressionType.None,

View File

@@ -105,6 +105,29 @@ public class SevenZipArchiveTests : ArchiveTests
new SevenZipFactory()
);
[Theory]
[InlineData("7Zip.LZMA.Aes.7z")]
[InlineData("7Zip.LZMA2.Aes.7z")]
public void SevenZipArchive_Aes_ReportsCompressionType(string testArchive)
{
// 7-Zip writes 7zAES as the folder's first coder, in front of the codec.
using var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, testArchive));
using var archive = SevenZipArchive.OpenArchive(
stream,
ReaderOptions.ForExternalStream with
{
Password = "testpassword",
}
);
var files = archive.Entries.Where(entry => !entry.IsDirectory && entry.Size > 0).ToList();
Assert.NotEmpty(files);
foreach (var entry in files)
{
Assert.True(entry.IsEncrypted, entry.Key);
Assert.Equal(CompressionType.LZMA, entry.CompressionType);
}
}
[Fact]
public void SevenZipArchive_LZMA2AES_StreamRead() =>
ArchiveStreamRead(