diff --git a/src/ICSharpCode.SharpZipLib/Zip/Compression/Streams/DeflaterOutputStream.cs b/src/ICSharpCode.SharpZipLib/Zip/Compression/Streams/DeflaterOutputStream.cs index b655bca19..03cac7358 100644 --- a/src/ICSharpCode.SharpZipLib/Zip/Compression/Streams/DeflaterOutputStream.cs +++ b/src/ICSharpCode.SharpZipLib/Zip/Compression/Streams/DeflaterOutputStream.cs @@ -379,7 +379,7 @@ public override int Read(byte[] buffer, int offset, int count) } /// - /// Flushes the stream by calling Flush on the deflater and then + /// Flushes the stream by calling Flush on the deflater and then /// on the underlying stream. This ensures that all bytes are flushed. /// public override void Flush() diff --git a/src/ICSharpCode.SharpZipLib/Zip/ZipFile.cs b/src/ICSharpCode.SharpZipLib/Zip/ZipFile.cs index 003881988..51618968c 100644 --- a/src/ICSharpCode.SharpZipLib/Zip/ZipFile.cs +++ b/src/ICSharpCode.SharpZipLib/Zip/ZipFile.cs @@ -1069,10 +1069,15 @@ private long TestLocalHeader(ZipEntry entry, HeaderTest tests) bool testHeader = (tests & HeaderTest.Header) != 0; bool testData = (tests & HeaderTest.Extract) != 0; - baseStream_.Seek(offsetOfFirstEntry + entry.Offset, SeekOrigin.Begin); - if ((int)ReadLEUint() != ZipConstants.LocalHeaderSignature) + var entryAbsOffset = offsetOfFirstEntry + entry.Offset; + + baseStream_.Seek(entryAbsOffset, SeekOrigin.Begin); + var signature = (int)ReadLEUint(); + + if (signature != ZipConstants.LocalHeaderSignature) { - throw new ZipException(string.Format("Wrong local header signature @{0:X}", offsetOfFirstEntry + entry.Offset)); + throw new ZipException(string.Format("Wrong local header signature at 0x{0:x}, expected 0x{1:x8}, actual 0x{2:x8}", + entryAbsOffset, ZipConstants.LocalHeaderSignature, signature)); } var extractVersion = (short)(ReadLEUshort() & 0x00ff); diff --git a/src/ICSharpCode.SharpZipLib/Zip/ZipOutputStream.cs b/src/ICSharpCode.SharpZipLib/Zip/ZipOutputStream.cs index c3dd31af2..b9f1965dd 100644 --- a/src/ICSharpCode.SharpZipLib/Zip/ZipOutputStream.cs +++ b/src/ICSharpCode.SharpZipLib/Zip/ZipOutputStream.cs @@ -887,6 +887,22 @@ public override void Finish() entries = null; } + /// + /// Flushes the stream by calling Flush on the deflater stream unless + /// the current compression method is . Then it flushes the underlying output stream. + /// + public override void Flush() + { + if(curMethod == CompressionMethod.Stored) + { + baseOutputStream_.Flush(); + } + else + { + base.Flush(); + } + } + #region Instance Fields /// diff --git a/test/ICSharpCode.SharpZipLib.Tests/TestSupport/RingBuffer.cs b/test/ICSharpCode.SharpZipLib.Tests/TestSupport/RingBuffer.cs index be351ae10..d4b75e3cf 100644 --- a/test/ICSharpCode.SharpZipLib.Tests/TestSupport/RingBuffer.cs +++ b/test/ICSharpCode.SharpZipLib.Tests/TestSupport/RingBuffer.cs @@ -405,6 +405,7 @@ public byte this[int index] } [TestFixture] + [Explicit("Meta tests (for ringbuffer)")] public class ExerciseBuffer { [Test] diff --git a/test/ICSharpCode.SharpZipLib.Tests/TestSupport/Utils.cs b/test/ICSharpCode.SharpZipLib.Tests/TestSupport/Utils.cs index 9a564c3c8..9c582daa6 100644 --- a/test/ICSharpCode.SharpZipLib.Tests/TestSupport/Utils.cs +++ b/test/ICSharpCode.SharpZipLib.Tests/TestSupport/Utils.cs @@ -1,6 +1,7 @@ using NUnit.Framework; using System; using System.IO; +using System.Text; namespace ICSharpCode.SharpZipLib.Tests.TestSupport { @@ -9,6 +10,8 @@ namespace ICSharpCode.SharpZipLib.Tests.TestSupport /// public static class Utils { + public static int DummyContentLength = 16; + private static Random random = new Random(); private static void Compare(byte[] a, byte[] b) @@ -32,16 +35,24 @@ private static void Compare(byte[] a, byte[] b) public static void WriteDummyData(string fileName, int size = -1) { - if (size < 0) + using(var fs = File.OpenWrite(fileName)) { - File.WriteAllText(fileName, DateTime.UtcNow.Ticks.ToString("x16")); + WriteDummyData(fs, size); } - else if (size > 0) + } + + public static void WriteDummyData(Stream stream, int size = -1) + { + var bytes = (size < 0) + ? Encoding.ASCII.GetBytes(DateTime.UtcNow.Ticks.ToString("x16")) + : new byte[size]; + + if(size > 0) { - var bytes = Array.CreateInstance(typeof(byte), size) as byte[]; random.NextBytes(bytes); - File.WriteAllBytes(fileName, bytes); } + + stream.Write(bytes, 0, bytes.Length); } public static TempFile GetDummyFile(int size = -1) @@ -85,7 +96,10 @@ protected virtual void Dispose(bool disposing) } public void Dispose() - => Dispose(true); + { + Dispose(true); + GC.SuppressFinalize(this); + } #endregion IDisposable Support } @@ -122,7 +136,10 @@ protected virtual void Dispose(bool disposing) } public void Dispose() - => Dispose(true); + { + Dispose(true); + GC.SuppressFinalize(this); + } internal string CreateDummyFile(int size = -1) => CreateDummyFile(GetDummyFileName(), size); diff --git a/test/ICSharpCode.SharpZipLib.Tests/Zip/FastZipHandling.cs b/test/ICSharpCode.SharpZipLib.Tests/Zip/FastZipHandling.cs index f16000699..25d53573f 100644 --- a/test/ICSharpCode.SharpZipLib.Tests/Zip/FastZipHandling.cs +++ b/test/ICSharpCode.SharpZipLib.Tests/Zip/FastZipHandling.cs @@ -93,6 +93,32 @@ public void ExtractEmptyDirectories() Assert.IsTrue(Directory.Exists(targetDir), "Empty directory should be created"); } + [Test] + [Category("Zip")] + [Category("CreatesTempFile")] + public void ContentEqualAfterAfterArchived([Values(0, 1, 64)]int contentSize) + { + using(var sourceDir = new Utils.TempDir()) + using(var targetDir = new Utils.TempDir()) + using(var zipFile = Utils.GetDummyFile(0)) + { + var sourceFile = sourceDir.CreateDummyFile(contentSize); + var sourceContent = File.ReadAllBytes(sourceFile); + new FastZip().CreateZip(zipFile.Filename, sourceDir.Fullpath, true, null); + + Assert.DoesNotThrow(() => + { + new FastZip().ExtractZip(zipFile.Filename, targetDir.Fullpath, null); + }, "Exception during extraction of test archive"); + + var targetFile = Path.Combine(targetDir.Fullpath, Path.GetFileName(sourceFile)); + var targetContent = File.ReadAllBytes(targetFile); + + Assert.AreEqual(sourceContent.Length, targetContent.Length, "Extracted file size does not match source file size"); + Assert.AreEqual(sourceContent, targetContent, "Extracted content does not match source content"); + } + } + [Test] [Category("Zip")] public void Encryption() diff --git a/test/ICSharpCode.SharpZipLib.Tests/Zip/StreamHandling.cs b/test/ICSharpCode.SharpZipLib.Tests/Zip/StreamHandling.cs index a2a9f635b..11aa1b213 100644 --- a/test/ICSharpCode.SharpZipLib.Tests/Zip/StreamHandling.cs +++ b/test/ICSharpCode.SharpZipLib.Tests/Zip/StreamHandling.cs @@ -1,4 +1,5 @@ -using ICSharpCode.SharpZipLib.Tests.TestSupport; +using ICSharpCode.SharpZipLib.Core; +using ICSharpCode.SharpZipLib.Tests.TestSupport; using ICSharpCode.SharpZipLib.Zip; using NUnit.Framework; using System.IO; @@ -190,6 +191,53 @@ public void EmptyZipEntries() Assert.AreEqual(extractCount, 0, "No data should be read from empty entries"); } + [Test] + [Category("Zip")] + public void WriteZipStreamWithNoCompression([Values(0, 1, 256)] int contentLength) + { + var buffer = new byte[255]; + + using (var dummyZip = Utils.GetDummyFile(0)) + using (var inputFile = Utils.GetDummyFile(contentLength)) + { + using (var zipFileStream = File.OpenWrite(dummyZip.Filename)) + using (var zipOutputStream = new ZipOutputStream(zipFileStream)) + using (var inputFileStream = File.OpenRead(inputFile.Filename)) + { + zipOutputStream.PutNextEntry(new ZipEntry(inputFile.Filename) + { + CompressionMethod = CompressionMethod.Stored, + }); + + StreamUtils.Copy(inputFileStream, zipOutputStream, buffer); + } + + using (var zf = new ZipFile(dummyZip.Filename)) + { + var inputBytes = File.ReadAllBytes(inputFile.Filename); + + var inputFileName = ZipEntry.CleanName(inputFile.Filename); + var entry = zf.GetEntry(inputFileName); + Assert.IsNotNull(entry, "No entry matching source file \"{0}\" found in archive, found \"{1}\"", inputFileName, zf[0].Name); + + Assert.DoesNotThrow(() => + { + using (var entryStream = zf.GetInputStream(entry)) + { + var outputBytes = new byte[entryStream.Length]; + entryStream.Read(outputBytes, 0, outputBytes.Length); + + Assert.AreEqual(inputBytes, outputBytes, "Archive content does not match the source content"); + } + }, "Failed to locate entry stream in archive"); + + Assert.IsTrue(zf.TestArchive(testData: true), "Archive did not pass TestArchive"); + } + + + } + } + /// /// Empty zips can be created and read? /// diff --git a/test/ICSharpCode.SharpZipLib.Tests/Zip/ZipFileHandling.cs b/test/ICSharpCode.SharpZipLib.Tests/Zip/ZipFileHandling.cs index 6d9a1ea9c..9bae7f772 100644 --- a/test/ICSharpCode.SharpZipLib.Tests/Zip/ZipFileHandling.cs +++ b/test/ICSharpCode.SharpZipLib.Tests/Zip/ZipFileHandling.cs @@ -615,6 +615,37 @@ public void CreateEmptyArchive() File.Delete(tempFile); } + [Test] + [Category("Zip")] + [Category("CreatesTempFile")] + public void CreateArchiveWithNoCompression() + { + + using (var sourceFile = Utils.GetDummyFile()) + using (var zipFile = Utils.GetDummyFile(0)) + { + var inputContent = File.ReadAllText(sourceFile.Filename); + using (ZipFile f = ZipFile.Create(zipFile.Filename)) + { + f.BeginUpdate(); + f.Add(sourceFile.Filename, CompressionMethod.Stored); + f.CommitUpdate(); + Assert.IsTrue(f.TestArchive(true)); + f.Close(); + } + + using (ZipFile f = new ZipFile(zipFile.Filename)) + { + Assert.AreEqual(1, f.Count); + using (var sr = new StreamReader(f.GetInputStream(f[0]))) + { + var outputContent = sr.ReadToEnd(); + Assert.AreEqual(inputContent, outputContent, "extracted content does not match source content"); + } + } + } + } + /// /// Check that ZipFile finds entries when its got a long comment /// @@ -1089,8 +1120,8 @@ public void NameFactory() var names = new string[] { "\u030A\u03B0", // Greek - "\u0680\u0685" // Arabic - }; + "\u0680\u0685" // Arabic + }; foreach (string name in names) {