| File: System\IO\Packaging\ZipStreamManager.cs | Web Access |
| Project: src\runtime\src\libraries\System.IO.Packaging\src\System.IO.Packaging.csproj (System.IO.Packaging) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Generic; using System.IO.Compression; using System.Text; using System.Threading.Tasks; namespace System.IO.Packaging { internal sealed class ZipStreamManager { private readonly ZipArchive _zipArchive; private readonly FileAccess _packageFileAccess; private readonly FileMode _packageFileMode; public ZipStreamManager(ZipArchive zipArchive, FileMode packageFileMode, FileAccess packageFileAccess) { _zipArchive = zipArchive; _packageFileMode = packageFileMode; _packageFileAccess = packageFileAccess; } public Stream Open(ZipArchiveEntry zipArchiveEntry, FileAccess streamFileAccess, bool discardExistingContent = false, bool requireSeekableStream = false) { bool canRead = true; bool canWrite = true; switch (_packageFileAccess) { case FileAccess.Read: switch (streamFileAccess) { case FileAccess.Read: canRead = true; canWrite = false; break; case FileAccess.Write: canRead = false; canWrite = false; break; case FileAccess.ReadWrite: canRead = true; canWrite = false; break; } break; case FileAccess.Write: switch (streamFileAccess) { case FileAccess.Read: canRead = false; canWrite = false; break; case FileAccess.Write: canRead = false; canWrite = true; break; case FileAccess.ReadWrite: canRead = false; canWrite = true; break; } break; case FileAccess.ReadWrite: switch (streamFileAccess) { case FileAccess.Read: canRead = true; canWrite = false; break; case FileAccess.Write: canRead = false; canWrite = true; break; case FileAccess.ReadWrite: canRead = true; canWrite = true; break; } break; } // Choose the most efficient way to open the entry based on how the returned stream will be used. // In Update mode the parameterless Open() decompresses and loads the whole entry into memory: // - When the entry will be overwritten (discardExistingContent, e.g. FileMode.Create), open with // FileAccess.Write to discard the existing content without loading it just to truncate it. // - When the caller only reads (canRead && !canWrite), open with FileAccess.Read to stream directly // from the archive instead of buffering the whole entry in memory. NOTE: for compressed entries // the resulting stream is forward-only (not seekable) and reflects the on-disk content only, so // callers that need to seek (e.g. the interleaved part reader) opt out via requireSeekableStream. Stream ns; #if NET11_0_OR_GREATER ns = (_zipArchive.Mode, discardExistingContent, canRead, canWrite, requireSeekableStream) switch { (ZipArchiveMode.Update, true, _, _, _) => zipArchiveEntry.Open(FileAccess.Write), (ZipArchiveMode.Update, false, true, false, false) => zipArchiveEntry.Open(FileAccess.Read), _ => zipArchiveEntry.Open(), }; #else ns = zipArchiveEntry.Open(); #endif return new ZipWrappingStream(zipArchiveEntry, ns, _packageFileMode, _packageFileAccess, canRead, canWrite); } } }