Skip to content

Commit 716b913

Browse files
authored
PR #355: Wire up BZip2 compression support for Zip files
1 parent 6ffe3c1 commit 716b913

File tree

5 files changed

+172
-3
lines changed

5 files changed

+172
-3
lines changed

src/ICSharpCode.SharpZipLib/Zip/ZipConstants.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,11 @@ public static class ZipConstants
281281
/// </summary>
282282
public const int VersionZip64 = 45;
283283

284+
/// <summary>
285+
/// The version required for BZip2 compression (4.6 or higher)
286+
/// </summary>
287+
public const int VersionBZip2 = 46;
288+
284289
#endregion Versions
285290

286291
#region Header Sizes

src/ICSharpCode.SharpZipLib/Zip/ZipEntry.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,10 @@ public int Version
585585
{
586586
result = 20;
587587
}
588+
else if (CompressionMethod.BZip2 == method)
589+
{
590+
result = ZipConstants.VersionBZip2;
591+
}
588592
else if (IsDirectory == true)
589593
{
590594
result = 20;
@@ -616,6 +620,7 @@ public bool CanDecompress
616620
(Version == 11) ||
617621
(Version == 20) ||
618622
(Version == 45) ||
623+
(Version == 46) ||
619624
(Version == 51)) &&
620625
IsCompressionMethodSupported();
621626
}
@@ -1290,7 +1295,8 @@ public static bool IsCompressionMethodSupported(CompressionMethod method)
12901295
{
12911296
return
12921297
(method == CompressionMethod.Deflated) ||
1293-
(method == CompressionMethod.Stored);
1298+
(method == CompressionMethod.Stored) ||
1299+
(method == CompressionMethod.BZip2);
12941300
}
12951301

12961302
/// <summary>

src/ICSharpCode.SharpZipLib/Zip/ZipFile.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -883,6 +883,10 @@ public Stream GetInputStream(long entryIndex)
883883
result = new InflaterInputStream(result, new Inflater(true));
884884
break;
885885

886+
case CompressionMethod.BZip2:
887+
result = new BZip2.BZip2InputStream(result);
888+
break;
889+
886890
default:
887891
throw new ZipException("Unsupported compression method " + method);
888892
}
@@ -1899,7 +1903,7 @@ public void AddDirectory(string directoryName)
18991903
/// <param name="compressionMethod">The compression method for the new entry.</param>
19001904
private void CheckSupportedCompressionMethod(CompressionMethod compressionMethod)
19011905
{
1902-
if (compressionMethod != CompressionMethod.Deflated && compressionMethod != CompressionMethod.Stored)
1906+
if (compressionMethod != CompressionMethod.Deflated && compressionMethod != CompressionMethod.Stored && compressionMethod != CompressionMethod.BZip2)
19031907
{
19041908
throw new NotImplementedException("Compression method not supported");
19051909
}
@@ -2636,6 +2640,16 @@ private Stream GetOutputStream(ZipEntry entry)
26362640
result = dos;
26372641
break;
26382642

2643+
case CompressionMethod.BZip2:
2644+
var bzos = new BZip2.BZip2OutputStream(result)
2645+
{
2646+
// If there is an encryption stream in use, then we want that to be disposed when the BZip2OutputStream stream is disposed
2647+
// If not, then we don't want it to dispose the base stream
2648+
IsStreamOwner = entry.IsCrypted
2649+
};
2650+
result = bzos;
2651+
break;
2652+
26392653
default:
26402654
throw new ZipException("Unknown compression method " + entry.CompressionMethod);
26412655
}

test/ICSharpCode.SharpZipLib.Tests/Zip/GeneralHandling.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ public void UnsupportedCompressionMethod()
141141
var ze = new ZipEntry("HumblePie");
142142
//ze.CompressionMethod = CompressionMethod.BZip2;
143143

144-
Assert.That(() => ze.CompressionMethod = CompressionMethod.BZip2,
144+
Assert.That(() => ze.CompressionMethod = CompressionMethod.Deflate64,
145145
Throws.TypeOf<NotSupportedException>());
146146
}
147147

test/ICSharpCode.SharpZipLib.Tests/Zip/ZipFileHandling.cs

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1611,5 +1611,149 @@ public void AddFileWithAlternateName()
16111611
}
16121612
}
16131613
}
1614+
1615+
/// <summary>
1616+
/// Test a zip file using BZip2 compression.
1617+
/// </summary>
1618+
[TestCase(true)]
1619+
[TestCase(false)]
1620+
[Category("Zip")]
1621+
public void ZipWithBZip2Compression(bool encryptEntries)
1622+
{
1623+
string password = "pwd";
1624+
1625+
using (var memStream = new MemoryStream())
1626+
{
1627+
using (ZipFile f = new ZipFile(memStream, leaveOpen: true))
1628+
{
1629+
if (encryptEntries)
1630+
f.Password = password;
1631+
1632+
f.BeginUpdate(new MemoryArchiveStorage());
1633+
1634+
var m = new StringMemoryDataSource("BZip2Compressed");
1635+
f.Add(m, "a.dat", CompressionMethod.BZip2);
1636+
1637+
var m2 = new StringMemoryDataSource("DeflateCompressed");
1638+
f.Add(m2, "b.dat", CompressionMethod.Deflated);
1639+
f.CommitUpdate();
1640+
Assert.IsTrue(f.TestArchive(true));
1641+
}
1642+
1643+
memStream.Seek(0, SeekOrigin.Begin);
1644+
1645+
using (ZipFile f = new ZipFile(memStream))
1646+
{
1647+
if (encryptEntries)
1648+
f.Password = password;
1649+
1650+
{
1651+
var entry = f.GetEntry("a.dat");
1652+
Assert.That(entry.CompressionMethod, Is.EqualTo(CompressionMethod.BZip2), "Compression method should be BZip2");
1653+
Assert.That(entry.Version, Is.EqualTo(ZipConstants.VersionBZip2), "Entry version should be 46");
1654+
Assert.That(entry.IsCrypted, Is.EqualTo(encryptEntries));
1655+
1656+
using (var reader = new StreamReader(f.GetInputStream(entry)))
1657+
{
1658+
string contents = reader.ReadToEnd();
1659+
Assert.That(contents, Is.EqualTo("BZip2Compressed"), "extract string must match original string");
1660+
}
1661+
}
1662+
1663+
{
1664+
var entry = f.GetEntry("b.dat");
1665+
Assert.That(entry.CompressionMethod, Is.EqualTo(CompressionMethod.Deflated), "Compression method should be Deflated");
1666+
Assert.That(entry.IsCrypted, Is.EqualTo(encryptEntries));
1667+
1668+
using (var reader = new StreamReader(f.GetInputStream(entry)))
1669+
{
1670+
string contents = reader.ReadToEnd();
1671+
Assert.That(contents, Is.EqualTo("DeflateCompressed"), "extract string must match original string");
1672+
}
1673+
}
1674+
}
1675+
1676+
// @@TODO@@ verify the archive with 7-zip?
1677+
}
1678+
}
1679+
1680+
/// <summary>
1681+
/// We should be able to read a bzip2 compressed zip file created by 7-zip.
1682+
/// </summary>
1683+
[Test]
1684+
[Category("Zip")]
1685+
public void ShouldReadBZip2ZipCreatedBy7Zip()
1686+
{
1687+
const string BZip2CompressedZipCreatedBy7Zip =
1688+
"UEsDBC4AAAAMAIa50U4/rHf5qwAAAK8AAAAJAAAASGVsbG8udHh0QlpoOTFBWSZTWTL8pwYAA" +
1689+
"BWfgEhlUAAiLUgQP+feMCAAiCKaeiaBobU9JiaAMGmoak9GmRNqPUDQ9T1PQsz/t9B6YvEdvF" +
1690+
"5dhwXzGE1ooO41A6TtATBEFxFUq6trGtUcSJDyWWWj/S2VwY15fy3IqHi3hHUS+K76zdoDzQa" +
1691+
"VGE/4YkYZe3JAtv1EsIqIsiTnnktIbBo1R4xY3JZEOm2BvwLuSKcKEgZflODAUEsBAj8ALgAA" +
1692+
"AAwAhrnRTj+sd/mrAAAArwAAAAkAJAAAAAAAAAAgAAAAAAAAAEhlbGxvLnR4dAoAIAAAAAAAA" +
1693+
"QAYAO97MLZZJdUB73swtlkl1QEK0UTFWCXVAVBLBQYAAAAAAQABAFsAAADSAAAAAAA=";
1694+
1695+
const string OriginalText =
1696+
"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.";
1697+
1698+
var fileBytes = System.Convert.FromBase64String(BZip2CompressedZipCreatedBy7Zip);
1699+
1700+
using (var input = new MemoryStream(fileBytes, false))
1701+
{
1702+
using (ZipFile f = new ZipFile(input))
1703+
{
1704+
var entry = f.GetEntry("Hello.txt");
1705+
Assert.That(entry.CompressionMethod, Is.EqualTo(CompressionMethod.BZip2), "Compression method should be BZip2");
1706+
Assert.That(entry.Version, Is.EqualTo(ZipConstants.VersionBZip2), "Entry version should be 46");
1707+
1708+
using (var reader = new StreamReader(f.GetInputStream(entry)))
1709+
{
1710+
string contents = reader.ReadToEnd();
1711+
Assert.That(contents, Is.EqualTo(OriginalText), "extract string must match original string");
1712+
}
1713+
}
1714+
}
1715+
}
1716+
1717+
/// <summary>
1718+
/// We should be able to read a bzip2 compressed / AES encrypted zip file created by 7-zip.
1719+
/// </summary>
1720+
[Test]
1721+
[Category("Zip")]
1722+
public void ShouldReadAESBZip2ZipCreatedBy7Zip()
1723+
{
1724+
const string BZip2CompressedZipCreatedBy7Zip =
1725+
"UEsDBDMAAQBjAIa50U4AAAAAxwAAAK8AAAAJAAsASGVsbG8udHh0AZkHAAIAQUUDDAAYg6jqf" +
1726+
"kvZClVMOtgmqKT0/8I9fMPgo96myxw9hLQUhKj1Qczi3fT7QIhAnAKU+u03nA8rCKGWmDI5Qz" +
1727+
"qPREy95boQVDPwmwEsWksv3GAWzMfzZUhmB/TgIJlA34a4yP0f2ucy3/QCQYo8QcHjBtjWX5b" +
1728+
"dZn0+fwY9Ci7q8JSI8zNSbgQ0Ert/lIJ9MxQ4lzBxMl4LySkd104cDPh/FslTAcPtHoy8Mf1c" +
1729+
"vnI1uICMgjWVeTqYrvSvt2uuHnqr4AiehArFiXTnUEsBAj8AMwABAGMAhrnRTgAAAADHAAAAr" +
1730+
"wAAAAkALwAAAAAAAAAgAAAAAAAAAEhlbGxvLnR4dAoAIAAAAAAAAQAYAO97MLZZJdUBYdnjul" +
1731+
"kl1QEK0UTFWCXVAQGZBwACAEFFAwwAUEsFBgAAAAABAAEAZgAAAPkAAAAAAA==";
1732+
1733+
const string OriginalText =
1734+
"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.";
1735+
1736+
var fileBytes = System.Convert.FromBase64String(BZip2CompressedZipCreatedBy7Zip);
1737+
1738+
using (var input = new MemoryStream(fileBytes, false))
1739+
{
1740+
using (ZipFile f = new ZipFile(input))
1741+
{
1742+
f.Password = "password";
1743+
1744+
var entry = f.GetEntry("Hello.txt");
1745+
Assert.That(entry.CompressionMethod, Is.EqualTo(CompressionMethod.BZip2), "Compression method should be BZip2");
1746+
Assert.That(entry.Version, Is.EqualTo(ZipConstants.VERSION_AES), "Entry version should be 51");
1747+
Assert.That(entry.IsCrypted, Is.True, "Entry should be encrypted");
1748+
Assert.That(entry.AESKeySize, Is.EqualTo(256), "AES Keysize should be 256");
1749+
1750+
using (var reader = new StreamReader(f.GetInputStream(entry)))
1751+
{
1752+
string contents = reader.ReadToEnd();
1753+
Assert.That(contents, Is.EqualTo(OriginalText), "extract string must match original string");
1754+
}
1755+
}
1756+
}
1757+
}
16141758
}
16151759
}

0 commit comments

Comments
 (0)