Skip to content

Commit

Permalink
Wire up BZip2 compression support for Zip files.
Browse files Browse the repository at this point in the history
  • Loading branch information
Numpsy committed Aug 16, 2020
1 parent 33cf8c4 commit d55456a
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 3 deletions.
5 changes: 5 additions & 0 deletions src/ICSharpCode.SharpZipLib/Zip/ZipConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,11 @@ public static class ZipConstants
/// </summary>
public const int VersionZip64 = 45;

/// <summary>
/// The version required for BZip2 compression (4.6 or higher)
/// </summary>
public const int VersionBZip2 = 46;

#endregion Versions

#region Header Sizes
Expand Down
8 changes: 7 additions & 1 deletion src/ICSharpCode.SharpZipLib/Zip/ZipEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,10 @@ public int Version
{
result = 20;
}
else if (CompressionMethod.BZip2 == method)
{
result = ZipConstants.VersionBZip2;
}
else if (IsDirectory == true)
{
result = 20;
Expand Down Expand Up @@ -616,6 +620,7 @@ public bool CanDecompress
(Version == 11) ||
(Version == 20) ||
(Version == 45) ||
(Version == 46) ||
(Version == 51)) &&
IsCompressionMethodSupported();
}
Expand Down Expand Up @@ -1290,7 +1295,8 @@ public static bool IsCompressionMethodSupported(CompressionMethod method)
{
return
(method == CompressionMethod.Deflated) ||
(method == CompressionMethod.Stored);
(method == CompressionMethod.Stored) ||
(method == CompressionMethod.BZip2);
}

/// <summary>
Expand Down
16 changes: 15 additions & 1 deletion src/ICSharpCode.SharpZipLib/Zip/ZipFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -883,6 +883,10 @@ public Stream GetInputStream(long entryIndex)
result = new InflaterInputStream(result, new Inflater(true));
break;

case CompressionMethod.BZip2:
result = new BZip2.BZip2InputStream(result);
break;

default:
throw new ZipException("Unsupported compression method " + method);
}
Expand Down Expand Up @@ -1899,7 +1903,7 @@ public void AddDirectory(string directoryName)
/// <param name="compressionMethod">The compression method for the new entry.</param>
private void CheckSupportedCompressionMethod(CompressionMethod compressionMethod)
{
if (compressionMethod != CompressionMethod.Deflated && compressionMethod != CompressionMethod.Stored)
if (compressionMethod != CompressionMethod.Deflated && compressionMethod != CompressionMethod.Stored && compressionMethod != CompressionMethod.BZip2)
{
throw new NotImplementedException("Compression method not supported");
}
Expand Down Expand Up @@ -2629,6 +2633,16 @@ private Stream GetOutputStream(ZipEntry entry)
result = dos;
break;

case CompressionMethod.BZip2:
var bzos = new BZip2.BZip2OutputStream(result)
{
// If there is an encryption stream in use, then we want that to be disposed when the BZip2OutputStream stream is disposed
// If not, then we don't want it to dispose the base stream
IsStreamOwner = entry.IsCrypted
};
result = bzos;
break;

default:
throw new ZipException("Unknown compression method " + entry.CompressionMethod);
}
Expand Down
2 changes: 1 addition & 1 deletion test/ICSharpCode.SharpZipLib.Tests/Zip/GeneralHandling.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ public void UnsupportedCompressionMethod()
var ze = new ZipEntry("HumblePie");
//ze.CompressionMethod = CompressionMethod.BZip2;

Assert.That(() => ze.CompressionMethod = CompressionMethod.BZip2,
Assert.That(() => ze.CompressionMethod = CompressionMethod.Deflate64,
Throws.TypeOf<NotSupportedException>());
}

Expand Down
144 changes: 144 additions & 0 deletions test/ICSharpCode.SharpZipLib.Tests/Zip/ZipFileHandling.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1611,5 +1611,149 @@ public void AddFileWithAlternateName()
}
}
}

/// <summary>
/// Test a zip file using BZip2 compression.
/// </summary>
[TestCase(true)]
[TestCase(false)]
[Category("Zip")]
public void ZipWithBZip2Compression(bool encryptEntries)
{
string password = "pwd";

using (var memStream = new MemoryStream())
{
using (ZipFile f = new ZipFile(memStream, leaveOpen: true))
{
if (encryptEntries)
f.Password = password;

f.BeginUpdate(new MemoryArchiveStorage());

var m = new StringMemoryDataSource("BZip2Compressed");
f.Add(m, "a.dat", CompressionMethod.BZip2);

var m2 = new StringMemoryDataSource("DeflateCompressed");
f.Add(m2, "b.dat", CompressionMethod.Deflated);
f.CommitUpdate();
Assert.IsTrue(f.TestArchive(true));
}

memStream.Seek(0, SeekOrigin.Begin);

using (ZipFile f = new ZipFile(memStream))
{
if (encryptEntries)
f.Password = password;

{
var entry = f.GetEntry("a.dat");
Assert.That(entry.CompressionMethod, Is.EqualTo(CompressionMethod.BZip2), "Compression method should be BZip2");
Assert.That(entry.Version, Is.EqualTo(ZipConstants.VersionBZip2), "Entry version should be 46");
Assert.That(entry.IsCrypted, Is.EqualTo(encryptEntries));

using (var reader = new StreamReader(f.GetInputStream(entry)))
{
string contents = reader.ReadToEnd();
Assert.That(contents, Is.EqualTo("BZip2Compressed"), "extract string must match original string");
}
}

{
var entry = f.GetEntry("b.dat");
Assert.That(entry.CompressionMethod, Is.EqualTo(CompressionMethod.Deflated), "Compression method should be Deflated");
Assert.That(entry.IsCrypted, Is.EqualTo(encryptEntries));

using (var reader = new StreamReader(f.GetInputStream(entry)))
{
string contents = reader.ReadToEnd();
Assert.That(contents, Is.EqualTo("DeflateCompressed"), "extract string must match original string");
}
}
}

// @@TODO@@ verify the archive with 7-zip?
}
}

/// <summary>
/// We should be able to read a bzip2 compressed zip file created by 7-zip.
/// </summary>
[Test]
[Category("Zip")]
public void ShouldReadBZip2ZipCreatedBy7Zip()
{
const string BZip2CompressedZipCreatedBy7Zip =
"UEsDBC4AAAAMAIa50U4/rHf5qwAAAK8AAAAJAAAASGVsbG8udHh0QlpoOTFBWSZTWTL8pwYAA" +
"BWfgEhlUAAiLUgQP+feMCAAiCKaeiaBobU9JiaAMGmoak9GmRNqPUDQ9T1PQsz/t9B6YvEdvF" +
"5dhwXzGE1ooO41A6TtATBEFxFUq6trGtUcSJDyWWWj/S2VwY15fy3IqHi3hHUS+K76zdoDzQa" +
"VGE/4YkYZe3JAtv1EsIqIsiTnnktIbBo1R4xY3JZEOm2BvwLuSKcKEgZflODAUEsBAj8ALgAA" +
"AAwAhrnRTj+sd/mrAAAArwAAAAkAJAAAAAAAAAAgAAAAAAAAAEhlbGxvLnR4dAoAIAAAAAAAA" +
"QAYAO97MLZZJdUB73swtlkl1QEK0UTFWCXVAVBLBQYAAAAAAQABAFsAAADSAAAAAAA=";

const string OriginalText =
"SharpZipLib (#ziplib, formerly NZipLib) is a compression library that supports Zip files using both stored and deflate compression methods, PKZIP 2.0 style and AES encryption.";

var fileBytes = System.Convert.FromBase64String(BZip2CompressedZipCreatedBy7Zip);

using (var input = new MemoryStream(fileBytes, false))
{
using (ZipFile f = new ZipFile(input))
{
var entry = f.GetEntry("Hello.txt");
Assert.That(entry.CompressionMethod, Is.EqualTo(CompressionMethod.BZip2), "Compression method should be BZip2");
Assert.That(entry.Version, Is.EqualTo(ZipConstants.VersionBZip2), "Entry version should be 46");

using (var reader = new StreamReader(f.GetInputStream(entry)))
{
string contents = reader.ReadToEnd();
Assert.That(contents, Is.EqualTo(OriginalText), "extract string must match original string");
}
}
}
}

/// <summary>
/// We should be able to read a bzip2 compressed / AES encrypted zip file created by 7-zip.
/// </summary>
[Test]
[Category("Zip")]
public void ShouldReadAESBZip2ZipCreatedBy7Zip()
{
const string BZip2CompressedZipCreatedBy7Zip =
"UEsDBDMAAQBjAIa50U4AAAAAxwAAAK8AAAAJAAsASGVsbG8udHh0AZkHAAIAQUUDDAAYg6jqf" +
"kvZClVMOtgmqKT0/8I9fMPgo96myxw9hLQUhKj1Qczi3fT7QIhAnAKU+u03nA8rCKGWmDI5Qz" +
"qPREy95boQVDPwmwEsWksv3GAWzMfzZUhmB/TgIJlA34a4yP0f2ucy3/QCQYo8QcHjBtjWX5b" +
"dZn0+fwY9Ci7q8JSI8zNSbgQ0Ert/lIJ9MxQ4lzBxMl4LySkd104cDPh/FslTAcPtHoy8Mf1c" +
"vnI1uICMgjWVeTqYrvSvt2uuHnqr4AiehArFiXTnUEsBAj8AMwABAGMAhrnRTgAAAADHAAAAr" +
"wAAAAkALwAAAAAAAAAgAAAAAAAAAEhlbGxvLnR4dAoAIAAAAAAAAQAYAO97MLZZJdUBYdnjul" +
"kl1QEK0UTFWCXVAQGZBwACAEFFAwwAUEsFBgAAAAABAAEAZgAAAPkAAAAAAA==";

const string OriginalText =
"SharpZipLib (#ziplib, formerly NZipLib) is a compression library that supports Zip files using both stored and deflate compression methods, PKZIP 2.0 style and AES encryption.";

var fileBytes = System.Convert.FromBase64String(BZip2CompressedZipCreatedBy7Zip);

using (var input = new MemoryStream(fileBytes, false))
{
using (ZipFile f = new ZipFile(input))
{
f.Password = "password";

var entry = f.GetEntry("Hello.txt");
Assert.That(entry.CompressionMethod, Is.EqualTo(CompressionMethod.BZip2), "Compression method should be BZip2");
Assert.That(entry.Version, Is.EqualTo(ZipConstants.VERSION_AES), "Entry version should be 51");
Assert.That(entry.IsCrypted, Is.True, "Entry should be encrypted");
Assert.That(entry.AESKeySize, Is.EqualTo(256), "AES Keysize should be 256");

using (var reader = new StreamReader(f.GetInputStream(entry)))
{
string contents = reader.ReadToEnd();
Assert.That(contents, Is.EqualTo(OriginalText), "extract string must match original string");
}
}
}
}
}
}

0 comments on commit d55456a

Please sign in to comment.