This is Xamarin's bug tracking system. For product support, please use the support links listed in your Xamarin Account.
Bug 39282 - [System.IO.Compression] issues with ZipArchiveEntry streams
Summary: [System.IO.Compression] issues with ZipArchiveEntry streams
Status: RESOLVED FIXED
Alias: None
Product: Class Libraries
Classification: Mono
Component: General (show other bugs)
Version: master
Hardware: PC Linux
: --- normal
Target Milestone: Untriaged
Assignee: João Matos
URL:
Depends on:
Blocks:
 
Reported: 2016-03-02 02:00 UTC by RichardW
Modified: 2016-06-29 10:44 UTC (History)
2 users (show)

See Also:
Tags:
Is this bug a regression?: ---
Last known good build:


Attachments

Description RichardW 2016-03-02 02:00:14 UTC
As mentioned at

https://bugzilla.xamarin.com/show_bug.cgi?id=33553#c46 
https://github.com/OfficeDev/Open-XML-SDK/issues/64


It Seems that the MS version of ZipArchiveEntry.Open (in some cases at least) returns a stream whose length can be queried, whereas the Mono version always throws.
Running the tests for the Microsoft Open XML SDK on Mono master gets a lot of failures due to it relying on being able to query the length (though as the linked issue says, the SDK contains its own workaround to make it work in some cases).

I know that DeflateStream doesn't support querying the length (as mentioned in #36638), however the documentation for ZipArchiveEntry.Open doesn't actually state the type of stream it returns, and as the MS implementation allows it in some cases this is at least an inconsistency in operation.
Comment 1 RichardW 2016-03-02 14:01:33 UTC
With a bit more testing, it seems that code along the lines of

/////
string _path = Path.Combine(Directory.GetCurrentDirectory(), "Temp-16ab1efb9254430987adc092eeb60c63.docx");

var _containerStream = new FileStream(_path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);


var zipArchive = new ZipArchive(_containerStream, ZipArchiveMode.Update, true, Encoding.UTF8);


var firstEntry = zipArchive.Entries [0].Open ();

using (StreamWriter sw = new StreamWriter(firstEntry))
{
    sw.Write("TEST");
}
/////

Will write to the stream when run on MS.NET, but throw a 'Stream is not writeable' exception on Mono. Seems like it should be possible to write to the stream when the archive is in update mode?
Comment 2 João Matos 2016-06-13 23:46:32 UTC
I'll look into it.
Comment 3 João Matos 2016-06-21 23:22:08 UTC
https://github.com/mono/mono/pull/3195
Comment 4 João Matos 2016-06-24 00:29:31 UTC
Second round of fixes: https://github.com/mono/mono/pull/3209
Comment 5 RichardW 2016-06-27 14:19:46 UTC
I had a go at running the Open XML SDK on the latest Mono master, and got a bunch of new failures along the lines of


System.IO.Packaging.Tests.Tests.T104_String_Create_ReadWrite_Open_Write [FAIL]
      SharpCompress.Common.ArchiveException : Cannot add entry with duplicate key: dummy.xml
      Stack Trace:
           at SharpCompress.Archive.AbstractWritableArchive`2[TEntry,TVolume].AddEntry (System.String key, System.IO.Stream source, System.Boolean closeStream, System.Int64 size, System.Nullable`1[T] modified) <0x10d965100 + 0x001bd> in <filename unknown>:0 
           at SharpCompress.Archive.AbstractWritableArchive`2[TEntry,TVolume].AddEntry (System.String key, System.IO.Stream source, System.Int64 size, System.Nullable`1[T] modified) <0x10d9650a0 + 0x00043> in <filename unknown>:0 
           at System.IO.Compression.ZipArchive.CreateEntryInternal (System.String entryName) <0x10d965010 + 0x00078> in <filename unknown>:0 
           at System.IO.Compression.ZipArchiveEntryStream.SetWriteable () <0x10d97f910 + 0x00056> in <filename unknown>:0 
           at System.IO.Compression.ZipArchiveEntryStream.Write (System.Byte[] buffer, System.Int32 offset, System.Int32 count) <0x10d97f870 + 0x0005d> in <filename unknown>:0 
           at System.IO.Packaging.ZipWrappingStream.Write (System.Byte[] buffer, System.Int32 offset, System.Int32 count) <0x10d97f830 + 0x00038> in <filename unknown>:0 
           at System.IO.StreamWriter.Flush (System.Boolean flushStream, System.Boolean flushEncoder) <0x10dc17ad0 + 0x00115> in <filename unknown>:0 


Which looks to be because code along the lines of

////
var mStream = new MemoryStream();
var zipArchive = new ZipArchive(mStream, ZipArchiveMode.Update);

var newEntry = zipArchive.CreateEntry("testEntry");

using (var newStream = newEntry.Open())
{
    using (var sw = new StreamWriter(newStream))
    {
        sw.Write("TEST");
    }
}
////

which runs ok in Mono 4.4 now throws with an error about duplicate entries on master.

It seems ok when working on existing archives that contain other entries, but looking at the code that might be because of another issue.

In System.IO.Compression/SharpCompress/Archive/AbstractWritableArchive.cs there is a DoesKeyMatchExisting function that looks like it should be checking the name of each entry in the archive but only actually checks the first.

As a test, If I do

var e2 = zipArchive.CreateEntry("BBB");
var e3 = zipArchive.CreateEntry("BBB");

Then I get an exception about duplicate errors, but if I do 

var e1 = zipArchive.CreateEntry("AAA");
var e2 = zipArchive.CreateEntry("BBB");
var e3 = zipArchive.CreateEntry("BBB");

then I don't, which doesn't seem right.
Comment 6 João Matos 2016-06-28 17:08:46 UTC
One more fix: https://github.com/mono/mono/pull/3214
Comment 7 João Matos 2016-06-29 10:44:26 UTC
Marking this one as fixed now that all the PRs landed.

For the duplicate entries problem:
https://bugzilla.xamarin.com/show_bug.cgi?id=42219
https://github.com/mono/mono/pull/3216

Note You need to log in before you can comment on or make changes to this bug.