[System.IO.Compression] Fixed Zip entry stream length/position getters in Update...
authorJoão Matos <joao@tritao.eu>
Thu, 30 Jun 2016 12:58:27 +0000 (13:58 +0100)
committerJoão Matos <joao@tritao.eu>
Thu, 30 Jun 2016 13:15:52 +0000 (14:15 +0100)
This does away with the lazy writeable entry scheme in Update mode and converts the stream to be writeable when its opened in Update mode.

From local testing, .NET does the same in this case.

Fixes another issue reported by @Numpsy in https://github.com/OfficeDev/Open-XML-SDK/issues/64.

Fixes https://bugzilla.xamarin.com/show_bug.cgi?id=42274.

mcs/class/System.IO.Compression/Test/System.IO.Compression/ZipTest.cs
mcs/class/System.IO.Compression/ZipArchiveEntry.cs

index 996921630022b23d946b5349be4a4052a1aa93e9..b9bb81011857ee564ee4c5c2c63cabd157e9f2c9 100644 (file)
@@ -275,11 +275,10 @@ namespace MonoTests.System.IO.Compression
                        }
                }
 
-               [Test]
-               public void ZipGetArchiveEntryStreamLengthPositionReadMode()
+               public void ZipGetArchiveEntryStreamLengthPosition(ZipArchiveMode mode)
                {
-                       using (var archive = new ZipArchive(File.Open("test.nupkg", FileMode.Open),
-                               ZipArchiveMode.Read))
+                       File.Copy("test.nupkg", "test2.nupkg", overwrite: true);
+                       using (var archive = new ZipArchive(File.Open("test2.nupkg", FileMode.Open), mode))
                        {
                                var entry = archive.GetEntry("_rels/.rels");
                                using (var stream = entry.Open())
@@ -287,9 +286,33 @@ namespace MonoTests.System.IO.Compression
                                        Assert.AreEqual(0, stream.Position);
                                        Assert.AreEqual(425, stream.Length);
                                }
+
+                               // .NET does not support these in Read mode but we do.
+                               var entry2 = archive.GetEntry("modernhttpclient.nuspec");
+                               using (var stream = entry2.Open())
+                               {
+                                       Assert.AreEqual(857, stream.Length);
+                                       if (mode == ZipArchiveMode.Update)
+                                       {
+                                               Assert.AreEqual(0, stream.Position);
+                                       }
+                               }
                        }
+                       File.Delete ("test2.nupkg");    
                }
 
+               [Test]
+               public void ZipGetArchiveEntryStreamLengthPositionReadMode()
+               {
+                       ZipGetArchiveEntryStreamLengthPosition(ZipArchiveMode.Read);
+               }
+
+               [Test]
+               public void ZipGetArchiveEntryStreamLengthPositionUpdateMode()
+               {
+                       ZipGetArchiveEntryStreamLengthPosition(ZipArchiveMode.Update);
+               }               
+
                [Test]
                public void ZipEnumerateEntriesReadMode()
                {
index 002b6f14cebf24b891867403223f977f7c3b6b5f..9b415fbe6fd6a31487539a655c6a99bbe46b1644 100644 (file)
@@ -54,7 +54,7 @@ namespace System.IO.Compression
 
                public override long Length {
                        get {
-                               return stream.Length;
+                               return stream.CanWrite ? stream.Length : entry.Length;
                        }
                }
 
@@ -95,15 +95,16 @@ namespace System.IO.Compression
 
                public override void Write (byte[] buffer, int offset, int count)
                {
-                       if (entry.Archive.Mode == ZipArchiveMode.Update && !entry.wasWritten)
+                       stream.Write(buffer, offset, count);
+               }
+
+               internal void EnsureWriteable()
+               {
+                       if (entry.Archive.Mode == ZipArchiveMode.Update && !stream.CanWrite)
                        {
                                // Replace the read-only stream with a writeable memory stream.
-                               if (!stream.CanWrite)
-                                   SetWriteable();
-                               entry.wasWritten = true;
+                               SetWriteable();
                        }
-
-                       stream.Write(buffer, offset, count);
                }
 
                internal void SetWriteable()
@@ -115,15 +116,11 @@ namespace System.IO.Compression
                        var newStream = newEntry.OpenEntryStream();
 
                        var openStream = stream;
-                       var position = openStream.Position;
-
-                       entry.openStream = null;
-                       entry.Open();
-
                        openStream.CopyTo(newStream);
-                       newStream.Position = position;
                        openStream.Dispose();
 
+                       newStream.Position = 0;
+
                        archive.zipFile.RemoveEntry(internalEntry);
                        entry.entry = newEntry;
                        stream = newStream;
@@ -232,6 +229,7 @@ namespace System.IO.Compression
 
                        var entryStream = entry.OpenEntryStream();
                        openStream = new ZipArchiveEntryStream(this, entryStream);
+                       openStream.EnsureWriteable();
 
                        return openStream;
                }