dotnet / wpf

WPF is a .NET Core UI framework for building Windows desktop applications.
MIT License
7.07k stars 1.17k forks source link

Behavior change regarding seekability of streams returned for ZipArchive #585

Closed ojhad closed 5 years ago

ojhad commented 5 years ago

There is a behavior change regarding the seekability of returned ZipArchiveEntry streams.

.NET Framework behavior:

The WindowsBase implementation of Zip had the necessary functionality that operated on the returned deflate streams which provided support for seeking (However, in doing so, it incurred a lot of extra CPU and file system usage)

.NET Core behavior: The current implementation in CoreFX (System.IO.Packaging) no longer provides this functionality, resulting in streams that are being returned to be non-seekable.

Related Issue: https://github.com/dotnet/corefx/issues/34219

jbartlau commented 5 years ago

I'm also having an issue with this exception if I call

var document = new XpsDocument(@"repro.xps", FileAccess.Read);
var paginatorSource = (IDocumentPaginatorSource)document.GetFixedDocumentSequence();

on the attached XPS file (which was created with the XPS Document Writer driver). See my comment at #575. Exception details:

System.NotSupportedException
  HResult=0x80131515
  Message=This operation is not supported.
  Source=System.IO.Compression
  StackTrace:
   at System.IO.Compression.DeflateStream.get_Position()
   at System.IO.Packaging.ZipWrappingStream.get_Position()
   at MS.Internal.IO.Packaging.SynchronizingStream.get_Position() in /_/src/Microsoft.DotNet.Wpf/src/shared/MS/Internal/IO/SynchronizingStream.cs:line 207
   at MS.Internal.IO.Packaging.DeobfuscatingStream.Read(Byte[] buffer, Int32 offset, Int32 count) in /_/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/Internal/IO/Packaging/DeobfuscatingStream.cs:line 56
   at MS.Internal.FontCache.FontSource.StreamToByteArray(Stream fontStream) in /_/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/Internal/FontCache/FontSource.cs:line 419
   at MS.Internal.FontCache.FontSource.GetUnmanagedStream() in /_/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/Internal/FontCache/FontSource.cs:line 279
   at MS.Internal.Text.TextInterface.FontFileStream..ctor(IFontSource fontSource)
   at MS.Internal.Text.TextInterface.FontFileLoader.CreateStreamFromKey(Void* fontFileReferenceKey, UInt32 fontFileReferenceKeySize, IntPtr* fontFileStream)

repro.zip

vatsan-madhavan commented 5 years ago

@grubioe - we need to document this issue as a change, and remove this from our queue. likely this is not going to actionable.

jbartlau commented 5 years ago

@vatsan-madhavan This will break Xps viewing and printing in a wide range of scenarios. IMHO this should be looked at at least for the Core 3.0 release.

weltkante commented 5 years ago

@vatsan-madhavan you have at least one more internal caller in WPF which is broken, see stack of @jbartlau, all internal callers need to be fixed

jbartlau commented 5 years ago

@weltkante @vatsan-madhavan Would be happy to raise a separate issue in order to tackle the internal call there.

vatsan-madhavan commented 5 years ago

@weltkante, @jbartlau, we are still looking into this. @jbartlau's issue (#1063) is helpful.

weltkante commented 5 years ago

@vatsan-madhavan the stack trace over in #1063 looks different than what @jbartlau reported, it seems to be a native exception and not directly related to the zip archive issue here and with @jbartlau.

rladuca commented 5 years ago

There is a working solution to this in branch, should be PRed later today: https://github.com/dotnet/wpf/tree/dev/roladuca/wrappackagestreams.

In summary, the DeflateStream implementation in System.IO.Compression is a non-seekable stream. This is returned to PackagePart.GetStream when it is opened as read-only. In these scenarios, we need to copy out the stream to a MemoryStream in order to be able to use Seek and Position. This is the essence of the fix that @stevenbrix did, but this attempts to address all such usages.

As a workaround (@jbartlau) you can open the Package as read/write (or XPS document, whatever API you are using). When you do this, the underlying packaging and compression APIs already uncompress to a MemoryStream and return that. So in those instances, we're given a proper seekable stream and things will work.

jbartlau commented 5 years ago

As a workaround (@jbartlau) you can open the Package as read/write (or XPS document, whatever API you are using).

Thanks @rladuca, can confirm the workaround is viable, will test the fix once it becomes available in one of the next previews then.

weltkante commented 5 years ago

Writing streams may need another look, wrapping them in MemoryStream needs special care to ensure the writes actually make it to the original stream and aren't lost when disposing the MemoryStream.

(Related to #1363 which is an example for actually writing and got me thinking about this case!)