Skip to content

Commit 20c10a5

Browse files
authored
Merge PR#406: Skip forced Deflate flush when using Stored compression
* Add tests for empty and stored files * Skip flushing deflate for Stored compression
1 parent 7fd6d65 commit 20c10a5

8 files changed

Lines changed: 158 additions & 14 deletions

File tree

src/ICSharpCode.SharpZipLib/Zip/Compression/Streams/DeflaterOutputStream.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ public override int Read(byte[] buffer, int offset, int count)
379379
}
380380

381381
/// <summary>
382-
/// Flushes the stream by calling <see cref="DeflaterOutputStream.Flush">Flush</see> on the deflater and then
382+
/// Flushes the stream by calling <see cref="Flush">Flush</see> on the deflater and then
383383
/// on the underlying stream. This ensures that all bytes are flushed.
384384
/// </summary>
385385
public override void Flush()

src/ICSharpCode.SharpZipLib/Zip/ZipFile.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,10 +1069,15 @@ private long TestLocalHeader(ZipEntry entry, HeaderTest tests)
10691069
bool testHeader = (tests & HeaderTest.Header) != 0;
10701070
bool testData = (tests & HeaderTest.Extract) != 0;
10711071

1072-
baseStream_.Seek(offsetOfFirstEntry + entry.Offset, SeekOrigin.Begin);
1073-
if ((int)ReadLEUint() != ZipConstants.LocalHeaderSignature)
1072+
var entryAbsOffset = offsetOfFirstEntry + entry.Offset;
1073+
1074+
baseStream_.Seek(entryAbsOffset, SeekOrigin.Begin);
1075+
var signature = (int)ReadLEUint();
1076+
1077+
if (signature != ZipConstants.LocalHeaderSignature)
10741078
{
1075-
throw new ZipException(string.Format("Wrong local header signature @{0:X}", offsetOfFirstEntry + entry.Offset));
1079+
throw new ZipException(string.Format("Wrong local header signature at 0x{0:x}, expected 0x{1:x8}, actual 0x{2:x8}",
1080+
entryAbsOffset, ZipConstants.LocalHeaderSignature, signature));
10761081
}
10771082

10781083
var extractVersion = (short)(ReadLEUshort() & 0x00ff);

src/ICSharpCode.SharpZipLib/Zip/ZipOutputStream.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -887,6 +887,22 @@ public override void Finish()
887887
entries = null;
888888
}
889889

890+
/// <summary>
891+
/// Flushes the stream by calling <see cref="DeflaterOutputStream.Flush">Flush</see> on the deflater stream unless
892+
/// the current compression method is <see cref="CompressionMethod.Stored"/>. Then it flushes the underlying output stream.
893+
/// </summary>
894+
public override void Flush()
895+
{
896+
if(curMethod == CompressionMethod.Stored)
897+
{
898+
baseOutputStream_.Flush();
899+
}
900+
else
901+
{
902+
base.Flush();
903+
}
904+
}
905+
890906
#region Instance Fields
891907

892908
/// <summary>

test/ICSharpCode.SharpZipLib.Tests/TestSupport/RingBuffer.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,7 @@ public byte this[int index]
405405
}
406406

407407
[TestFixture]
408+
[Explicit("Meta tests (for ringbuffer)")]
408409
public class ExerciseBuffer
409410
{
410411
[Test]

test/ICSharpCode.SharpZipLib.Tests/TestSupport/Utils.cs

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using NUnit.Framework;
22
using System;
33
using System.IO;
4+
using System.Text;
45

56
namespace ICSharpCode.SharpZipLib.Tests.TestSupport
67
{
@@ -9,6 +10,8 @@ namespace ICSharpCode.SharpZipLib.Tests.TestSupport
910
/// </summary>
1011
public static class Utils
1112
{
13+
public static int DummyContentLength = 16;
14+
1215
private static Random random = new Random();
1316

1417
private static void Compare(byte[] a, byte[] b)
@@ -32,16 +35,24 @@ private static void Compare(byte[] a, byte[] b)
3235

3336
public static void WriteDummyData(string fileName, int size = -1)
3437
{
35-
if (size < 0)
38+
using(var fs = File.OpenWrite(fileName))
3639
{
37-
File.WriteAllText(fileName, DateTime.UtcNow.Ticks.ToString("x16"));
40+
WriteDummyData(fs, size);
3841
}
39-
else if (size > 0)
42+
}
43+
44+
public static void WriteDummyData(Stream stream, int size = -1)
45+
{
46+
var bytes = (size < 0)
47+
? Encoding.ASCII.GetBytes(DateTime.UtcNow.Ticks.ToString("x16"))
48+
: new byte[size];
49+
50+
if(size > 0)
4051
{
41-
var bytes = Array.CreateInstance(typeof(byte), size) as byte[];
4252
random.NextBytes(bytes);
43-
File.WriteAllBytes(fileName, bytes);
4453
}
54+
55+
stream.Write(bytes, 0, bytes.Length);
4556
}
4657

4758
public static TempFile GetDummyFile(int size = -1)
@@ -85,7 +96,10 @@ protected virtual void Dispose(bool disposing)
8596
}
8697

8798
public void Dispose()
88-
=> Dispose(true);
99+
{
100+
Dispose(true);
101+
GC.SuppressFinalize(this);
102+
}
89103

90104
#endregion IDisposable Support
91105
}
@@ -122,7 +136,10 @@ protected virtual void Dispose(bool disposing)
122136
}
123137

124138
public void Dispose()
125-
=> Dispose(true);
139+
{
140+
Dispose(true);
141+
GC.SuppressFinalize(this);
142+
}
126143

127144
internal string CreateDummyFile(int size = -1)
128145
=> CreateDummyFile(GetDummyFileName(), size);

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,32 @@ public void ExtractEmptyDirectories()
9393
Assert.IsTrue(Directory.Exists(targetDir), "Empty directory should be created");
9494
}
9595

96+
[Test]
97+
[Category("Zip")]
98+
[Category("CreatesTempFile")]
99+
public void ContentEqualAfterAfterArchived([Values(0, 1, 64)]int contentSize)
100+
{
101+
using(var sourceDir = new Utils.TempDir())
102+
using(var targetDir = new Utils.TempDir())
103+
using(var zipFile = Utils.GetDummyFile(0))
104+
{
105+
var sourceFile = sourceDir.CreateDummyFile(contentSize);
106+
var sourceContent = File.ReadAllBytes(sourceFile);
107+
new FastZip().CreateZip(zipFile.Filename, sourceDir.Fullpath, true, null);
108+
109+
Assert.DoesNotThrow(() =>
110+
{
111+
new FastZip().ExtractZip(zipFile.Filename, targetDir.Fullpath, null);
112+
}, "Exception during extraction of test archive");
113+
114+
var targetFile = Path.Combine(targetDir.Fullpath, Path.GetFileName(sourceFile));
115+
var targetContent = File.ReadAllBytes(targetFile);
116+
117+
Assert.AreEqual(sourceContent.Length, targetContent.Length, "Extracted file size does not match source file size");
118+
Assert.AreEqual(sourceContent, targetContent, "Extracted content does not match source content");
119+
}
120+
}
121+
96122
[Test]
97123
[Category("Zip")]
98124
public void Encryption()

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

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using ICSharpCode.SharpZipLib.Tests.TestSupport;
1+
using ICSharpCode.SharpZipLib.Core;
2+
using ICSharpCode.SharpZipLib.Tests.TestSupport;
23
using ICSharpCode.SharpZipLib.Zip;
34
using NUnit.Framework;
45
using System.IO;
@@ -190,6 +191,53 @@ public void EmptyZipEntries()
190191
Assert.AreEqual(extractCount, 0, "No data should be read from empty entries");
191192
}
192193

194+
[Test]
195+
[Category("Zip")]
196+
public void WriteZipStreamWithNoCompression([Values(0, 1, 256)] int contentLength)
197+
{
198+
var buffer = new byte[255];
199+
200+
using (var dummyZip = Utils.GetDummyFile(0))
201+
using (var inputFile = Utils.GetDummyFile(contentLength))
202+
{
203+
using (var zipFileStream = File.OpenWrite(dummyZip.Filename))
204+
using (var zipOutputStream = new ZipOutputStream(zipFileStream))
205+
using (var inputFileStream = File.OpenRead(inputFile.Filename))
206+
{
207+
zipOutputStream.PutNextEntry(new ZipEntry(inputFile.Filename)
208+
{
209+
CompressionMethod = CompressionMethod.Stored,
210+
});
211+
212+
StreamUtils.Copy(inputFileStream, zipOutputStream, buffer);
213+
}
214+
215+
using (var zf = new ZipFile(dummyZip.Filename))
216+
{
217+
var inputBytes = File.ReadAllBytes(inputFile.Filename);
218+
219+
var inputFileName = ZipEntry.CleanName(inputFile.Filename);
220+
var entry = zf.GetEntry(inputFileName);
221+
Assert.IsNotNull(entry, "No entry matching source file \"{0}\" found in archive, found \"{1}\"", inputFileName, zf[0].Name);
222+
223+
Assert.DoesNotThrow(() =>
224+
{
225+
using (var entryStream = zf.GetInputStream(entry))
226+
{
227+
var outputBytes = new byte[entryStream.Length];
228+
entryStream.Read(outputBytes, 0, outputBytes.Length);
229+
230+
Assert.AreEqual(inputBytes, outputBytes, "Archive content does not match the source content");
231+
}
232+
}, "Failed to locate entry stream in archive");
233+
234+
Assert.IsTrue(zf.TestArchive(testData: true), "Archive did not pass TestArchive");
235+
}
236+
237+
238+
}
239+
}
240+
193241
/// <summary>
194242
/// Empty zips can be created and read?
195243
/// </summary>

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

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,37 @@ public void CreateEmptyArchive()
615615
File.Delete(tempFile);
616616
}
617617

618+
[Test]
619+
[Category("Zip")]
620+
[Category("CreatesTempFile")]
621+
public void CreateArchiveWithNoCompression()
622+
{
623+
624+
using (var sourceFile = Utils.GetDummyFile())
625+
using (var zipFile = Utils.GetDummyFile(0))
626+
{
627+
var inputContent = File.ReadAllText(sourceFile.Filename);
628+
using (ZipFile f = ZipFile.Create(zipFile.Filename))
629+
{
630+
f.BeginUpdate();
631+
f.Add(sourceFile.Filename, CompressionMethod.Stored);
632+
f.CommitUpdate();
633+
Assert.IsTrue(f.TestArchive(true));
634+
f.Close();
635+
}
636+
637+
using (ZipFile f = new ZipFile(zipFile.Filename))
638+
{
639+
Assert.AreEqual(1, f.Count);
640+
using (var sr = new StreamReader(f.GetInputStream(f[0])))
641+
{
642+
var outputContent = sr.ReadToEnd();
643+
Assert.AreEqual(inputContent, outputContent, "extracted content does not match source content");
644+
}
645+
}
646+
}
647+
}
648+
618649
/// <summary>
619650
/// Check that ZipFile finds entries when its got a long comment
620651
/// </summary>
@@ -1089,8 +1120,8 @@ public void NameFactory()
10891120
var names = new string[]
10901121
{
10911122
"\u030A\u03B0", // Greek
1092-
"\u0680\u0685" // Arabic
1093-
};
1123+
"\u0680\u0685" // Arabic
1124+
};
10941125

10951126
foreach (string name in names)
10961127
{

0 commit comments

Comments
 (0)