Annotate System.IO.Compression for nullable (dotnet/corefx#41322)
authorbuyaa-n <bunamnan@microsoft.com>
Fri, 27 Sep 2019 16:41:52 +0000 (09:41 -0700)
committerGitHub <noreply@github.com>
Fri, 27 Sep 2019 16:41:52 +0000 (09:41 -0700)
Nullable annotation for System.IO.Compression

Commit migrated from https://github.com/dotnet/corefx/commit/967eb3c5cb5fd36c8bb56d06f4c840f6a7a5a754

20 files changed:
src/libraries/Common/src/System/IO/PathInternal.Windows.cs
src/libraries/System.IO.Compression/ref/System.IO.Compression.cs
src/libraries/System.IO.Compression/ref/System.IO.Compression.csproj
src/libraries/System.IO.Compression/src/System.IO.Compression.csproj
src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateManaged/DeflateInput.cs [deleted file]
src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateManaged/DeflateManagedStream.cs
src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateManaged/HuffmanTree.cs
src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateManaged/InflaterManaged.cs
src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateManaged/InputBuffer.cs
src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateZLib/DeflateStream.cs
src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateZLib/Deflater.cs
src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateZLib/Inflater.cs
src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateZLib/ZLibException.cs
src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateZLib/ZLibNative.cs
src/libraries/System.IO.Compression/src/System/IO/Compression/GZipStream.cs
src/libraries/System.IO.Compression/src/System/IO/Compression/PositionPreservingWriteOnlyStreamWrapper.cs
src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchive.cs
src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs
src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.cs
src/libraries/System.IO.Compression/src/System/IO/Compression/ZipCustomStreams.cs

index a697899..1287b56 100644 (file)
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+#nullable enable
 using System.Runtime.CompilerServices;
 
 namespace System.IO
@@ -73,7 +74,8 @@ namespace System.IO
         /// away from paths during normalization, but if we see such a path at this point it should be
         /// normalized and has retained the final characters. (Typically from one of the *Info classes)
         /// </summary>
-        internal static string EnsureExtendedPrefixIfNeeded(string path)
+        /// TODO: add atribute [return: NotNullIfNotNull("path")]
+        internal static string? EnsureExtendedPrefixIfNeeded(string? path)
         {
             if (path != null && (path.Length >= MaxShortPath || EndsWithPeriodOrSpace(path)))
             {
index 0168c11..fbea7cc 100644 (file)
@@ -30,8 +30,8 @@ namespace System.IO.Compression
         public override bool CanWrite { get { throw null; } }
         public override long Length { get { throw null; } }
         public override long Position { get { throw null; } set { } }
-        public override System.IAsyncResult BeginRead(byte[] buffer, int offset, int count, System.AsyncCallback asyncCallback, object asyncState) { throw null; }
-        public override System.IAsyncResult BeginWrite(byte[] array, int offset, int count, System.AsyncCallback asyncCallback, object asyncState) { throw null; }
+        public override System.IAsyncResult BeginRead(byte[] buffer, int offset, int count, System.AsyncCallback? asyncCallback, object? asyncState) { throw null; }
+        public override System.IAsyncResult BeginWrite(byte[] array, int offset, int count, System.AsyncCallback? asyncCallback, object? asyncState) { throw null; }
         public override void CopyTo(System.IO.Stream destination, int bufferSize) { }
         public override System.Threading.Tasks.Task CopyToAsync(System.IO.Stream destination, int bufferSize, System.Threading.CancellationToken cancellationToken) { throw null; }
         protected override void Dispose(bool disposing) { }
@@ -64,8 +64,8 @@ namespace System.IO.Compression
         public override bool CanWrite { get { throw null; } }
         public override long Length { get { throw null; } }
         public override long Position { get { throw null; } set { } }
-        public override System.IAsyncResult BeginRead(byte[] array, int offset, int count, System.AsyncCallback asyncCallback, object asyncState) { throw null; }
-        public override System.IAsyncResult BeginWrite(byte[] array, int offset, int count, System.AsyncCallback asyncCallback, object asyncState) { throw null; }
+        public override System.IAsyncResult BeginRead(byte[] array, int offset, int count, System.AsyncCallback? asyncCallback, object? asyncState) { throw null; }
+        public override System.IAsyncResult BeginWrite(byte[] array, int offset, int count, System.AsyncCallback? asyncCallback, object? asyncState) { throw null; }
         public override void CopyTo(System.IO.Stream destination, int bufferSize) { }
         public override System.Threading.Tasks.Task CopyToAsync(System.IO.Stream destination, int bufferSize, System.Threading.CancellationToken cancellationToken) { throw null; }
         protected override void Dispose(bool disposing) { }
@@ -91,14 +91,14 @@ namespace System.IO.Compression
         public ZipArchive(System.IO.Stream stream) { }
         public ZipArchive(System.IO.Stream stream, System.IO.Compression.ZipArchiveMode mode) { }
         public ZipArchive(System.IO.Stream stream, System.IO.Compression.ZipArchiveMode mode, bool leaveOpen) { }
-        public ZipArchive(System.IO.Stream stream, System.IO.Compression.ZipArchiveMode mode, bool leaveOpen, System.Text.Encoding entryNameEncoding) { }
+        public ZipArchive(System.IO.Stream stream, System.IO.Compression.ZipArchiveMode mode, bool leaveOpen, System.Text.Encoding? entryNameEncoding) { }
         public System.Collections.ObjectModel.ReadOnlyCollection<System.IO.Compression.ZipArchiveEntry> Entries { get { throw null; } }
         public System.IO.Compression.ZipArchiveMode Mode { get { throw null; } }
         public System.IO.Compression.ZipArchiveEntry CreateEntry(string entryName) { throw null; }
         public System.IO.Compression.ZipArchiveEntry CreateEntry(string entryName, System.IO.Compression.CompressionLevel compressionLevel) { throw null; }
         public void Dispose() { }
         protected virtual void Dispose(bool disposing) { }
-        public System.IO.Compression.ZipArchiveEntry GetEntry(string entryName) { throw null; }
+        public System.IO.Compression.ZipArchiveEntry? GetEntry(string entryName) { throw null; }
     }
     public partial class ZipArchiveEntry
     {
index 108d194..21eac72 100644 (file)
@@ -1,6 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
     <Configurations>netcoreapp-Debug;netcoreapp-Release;uap-Debug;uap-Release</Configurations>
+    <Nullable>enable</Nullable>
   </PropertyGroup>
   <ItemGroup>
     <Compile Include="System.IO.Compression.cs" />
index 70bf5a4..0b2204a 100644 (file)
@@ -4,6 +4,7 @@
     <OutputType>Library</OutputType>
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
     <Configurations>netcoreapp-Unix-Debug;netcoreapp-Unix-Release;netcoreapp-Windows_NT-Debug;netcoreapp-Windows_NT-Release;uap-Windows_NT-Debug;uap-Windows_NT-Release</Configurations>
+    <Nullable>enable</Nullable>
   </PropertyGroup>
   <!-- Default configurations to help VS understand the options -->
   <ItemGroup>
@@ -16,7 +17,6 @@
     <Compile Include="$(SharedOpenSourcePath)System\IO\Compression\ZipHelper.cs" />
     <Compile Include="$(SharedOpenSourcePath)System\IO\Compression\ZipVersion.cs" />
     <Compile Include="System\IO\Compression\DeflateManaged\BlockType.cs" />
-    <Compile Include="System\IO\Compression\DeflateManaged\DeflateInput.cs" />
     <Compile Include="System\IO\Compression\DeflateManaged\DeflateManagedStream.cs" />
     <Compile Include="System\IO\Compression\DeflateManaged\FileFormats.cs" />
     <Compile Include="System\IO\Compression\DeflateManaged\HuffmanTree.cs" />
diff --git a/src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateManaged/DeflateInput.cs b/src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateManaged/DeflateInput.cs
deleted file mode 100644 (file)
index 64d793d..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Diagnostics;
-
-namespace System.IO.Compression
-{
-    internal sealed class DeflateInput
-    {
-        internal byte[] Buffer { get; set; }
-        internal int Count { get; set; }
-        internal int StartIndex { get; set; }
-
-        internal void ConsumeBytes(int n)
-        {
-            Debug.Assert(n <= Count, "Should use more bytes than what we have in the buffer");
-            StartIndex += n;
-            Count -= n;
-            Debug.Assert(StartIndex + Count <= Buffer.Length, "Input buffer is in invalid state!");
-        }
-
-        internal InputState DumpState() => new InputState(Count, StartIndex);
-
-        internal void RestoreState(InputState state)
-        {
-            Count = state._count;
-            StartIndex = state._startIndex;
-        }
-
-        internal readonly struct InputState
-        {
-            internal readonly int _count;
-            internal readonly int _startIndex;
-
-            internal InputState(int count, int startIndex)
-            {
-                _count = count;
-                _startIndex = startIndex;
-            }
-        }
-    }
-}
index dfadee5..df53b22 100644 (file)
@@ -14,38 +14,27 @@ namespace System.IO.Compression
     {
         internal const int DefaultBufferSize = 8192;
 
-        private Stream _stream;
-        private bool _leaveOpen;
+        private Stream? _stream;
         private InflaterManaged _inflater;
-        private byte[] _buffer;
+        private readonly byte[] _buffer;
 
         private int _asyncOperations;
 
         // A specific constructor to allow decompression of Deflate64
-        internal DeflateManagedStream(Stream stream, ZipArchiveEntry.CompressionMethodValues method, long uncompressedSize)
+        internal DeflateManagedStream(Stream stream, ZipArchiveEntry.CompressionMethodValues method, long uncompressedSize = -1)
         {
             if (stream == null)
                 throw new ArgumentNullException(nameof(stream));
             if (!stream.CanRead)
                 throw new ArgumentException(SR.NotSupported_UnreadableStream, nameof(stream));
-
-            InitializeInflater(stream, false, null, method, uncompressedSize);
-        }
-
-        /// <summary>
-        /// Sets up this DeflateManagedStream to be used for Inflation/Decompression
-        /// </summary>
-        internal void InitializeInflater(Stream stream, bool leaveOpen, IFileFormatReader reader = null, ZipArchiveEntry.CompressionMethodValues method = ZipArchiveEntry.CompressionMethodValues.Deflate, long uncompressedSize = -1)
-        {
-            Debug.Assert(stream != null);
-            Debug.Assert(method == ZipArchiveEntry.CompressionMethodValues.Deflate64);
             if (!stream.CanRead)
                 throw new ArgumentException(SR.NotSupported_UnreadableStream, nameof(stream));
 
-            _inflater = new InflaterManaged(reader, method == ZipArchiveEntry.CompressionMethodValues.Deflate64 ? true : false, uncompressedSize);
+            Debug.Assert(method == ZipArchiveEntry.CompressionMethodValues.Deflate64);
+
+            _inflater = new InflaterManaged(null, method == ZipArchiveEntry.CompressionMethodValues.Deflate64 ? true : false, uncompressedSize);
 
             _stream = stream;
-            _leaveOpen = leaveOpen;
             _buffer = new byte[DefaultBufferSize];
         }
 
@@ -133,7 +122,7 @@ namespace System.IO.Compression
                     break;
                 }
 
-                int bytes = _stream.Read(_buffer, 0, _buffer.Length);
+                int bytes = _stream!.Read(_buffer, 0, _buffer.Length);
                 if (bytes <= 0)
                 {
                     break;
@@ -177,7 +166,7 @@ namespace System.IO.Compression
             throw new ObjectDisposedException(null, SR.ObjectDisposed_StreamClosed);
         }
 
-        public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback asyncCallback, object asyncState) =>
+        public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? asyncCallback, object? asyncState) =>
             TaskToApm.Begin(ReadAsync(buffer, offset, count, CancellationToken.None), asyncCallback, asyncState);
 
         public override int EndRead(IAsyncResult asyncResult) =>
@@ -198,7 +187,7 @@ namespace System.IO.Compression
             }
 
             Interlocked.Increment(ref _asyncOperations);
-            Task<int> readTask = null;
+            Task<int>? readTask = null;
 
             try
             {
@@ -218,7 +207,7 @@ namespace System.IO.Compression
 
                 // If there is no data on the output buffer and we are not at
                 // the end of the stream, we need to get more data from the base stream
-                readTask = _stream.ReadAsync(_buffer, 0, _buffer.Length, cancellationToken);
+                readTask = _stream!.ReadAsync(_buffer, 0, _buffer.Length, cancellationToken);
                 if (readTask == null)
                 {
                     throw new InvalidOperationException(SR.NotSupported_UnreadableStream);
@@ -267,7 +256,7 @@ namespace System.IO.Compression
                     {
                         // We could have read in head information and didn't get any data.
                         // Read from the base stream again.
-                        readTask = _stream.ReadAsync(_buffer, 0, _buffer.Length, cancellationToken);
+                        readTask = _stream!.ReadAsync(_buffer, 0, _buffer.Length, cancellationToken);
                         if (readTask == null)
                         {
                             throw new InvalidOperationException(SR.NotSupported_UnreadableStream);
@@ -315,12 +304,12 @@ namespace System.IO.Compression
                 // In this case, we still need to clean up internal resources, hence the inner finally blocks.
                 try
                 {
-                    if (disposing && !_leaveOpen && _stream != null)
+                    if (disposing && _stream != null)
                         _stream.Dispose();
                 }
                 finally
                 {
-                    _stream = null;
+                    _stream = null!;
 
                     try
                     {
@@ -328,7 +317,7 @@ namespace System.IO.Compression
                     }
                     finally
                     {
-                        _inflater = null;
+                        _inflater = null!;
                         base.Dispose(disposing);
                     }
                 }
index fd031a6..2a4cee8 100644 (file)
@@ -34,7 +34,7 @@ namespace System.IO.Compression
         private readonly short[] _right;
         private readonly byte[] _codeLengthArray;
 #if DEBUG
-        private uint[] _codeArrayDebug;
+        private uint[]? _codeArrayDebug;
 #endif
 
         private readonly int _tableMask;
index e735ca1..d88e253 100644 (file)
@@ -45,8 +45,8 @@ namespace System.IO.Compression
 
         private readonly OutputWindow _output;
         private readonly InputBuffer _input;
-        private HuffmanTree _literalLengthTree;
-        private HuffmanTree _distanceTree;
+        private HuffmanTree? _literalLengthTree;
+        private HuffmanTree? _distanceTree;
 
         private InflaterState _state;
         private readonly bool _hasFormatReader;
@@ -72,13 +72,13 @@ namespace System.IO.Compression
         private readonly byte[] _codeList; // temporary array to store the code length for literal/Length and distance
         private readonly byte[] _codeLengthTreeCodeLength;
         private readonly bool _deflate64;
-        private HuffmanTree _codeLengthTree;
+        private HuffmanTree? _codeLengthTree;
         private readonly long _uncompressedSize;
         private long _currentInflatedCount;
 
-        private readonly IFileFormatReader _formatReader; // class to decode header and footer (e.g. gzip)
+        private readonly IFileFormatReader? _formatReader; // class to decode header and footer (e.g. gzip)
 
-        internal InflaterManaged(IFileFormatReader reader, bool deflate64, long uncompressedSize)
+        internal InflaterManaged(IFileFormatReader? reader, bool deflate64, long uncompressedSize)
         {
             _output = new OutputWindow();
             _input = new InputBuffer();
@@ -140,6 +140,7 @@ namespace System.IO.Compression
                 {
                     if (_hasFormatReader)
                     {
+                        Debug.Assert(_formatReader != null);
                         _formatReader.UpdateWithBytesRead(bytes, offset, copied);
                     }
 
@@ -161,6 +162,7 @@ namespace System.IO.Compression
                 // But some data in output window might not be copied out.
                 if (_output.AvailableBytes == 0)
                 {
+                    Debug.Assert(_formatReader != null);
                     _formatReader.Validate();
                 }
             }
@@ -201,6 +203,7 @@ namespace System.IO.Compression
 
             if (_hasFormatReader)
             {
+                Debug.Assert(_formatReader != null);
                 if (_state == InflaterState.ReadingHeader)
                 {
                     if (!_formatReader.ReadHeader(_input))
@@ -398,6 +401,7 @@ namespace System.IO.Compression
                     case InflaterState.DecodeTop:
                         // decode an element from the literal tree
 
+                        Debug.Assert(_literalLengthTree != null);
                         // TODO: optimize this!!!
                         symbol = _literalLengthTree.GetNextSymbol(_input);
                         if (symbol < 0)
@@ -471,6 +475,7 @@ namespace System.IO.Compression
                     case InflaterState.HaveFullLength:
                         if (_blockType == BlockType.Dynamic)
                         {
+                            Debug.Assert(_distanceTree != null);
                             _distanceCode = _distanceTree.GetNextSymbol(_input);
                         }
                         else
@@ -615,6 +620,7 @@ namespace System.IO.Compression
                     {
                         if (_state == InflaterState.ReadingTreeCodesBefore)
                         {
+                            Debug.Assert(_codeLengthTree != null);
                             if ((_lengthCode = _codeLengthTree.GetNextSymbol(_input)) < 0)
                             {
                                 return false;
index e17b2e8..13efb3e 100644 (file)
@@ -18,7 +18,7 @@ namespace System.IO.Compression
 
     internal sealed class InputBuffer
     {
-        private byte[] _buffer;           // byte array to store input
+        private byte[]? _buffer;           // byte array to store input
         private int _start;               // start poisition of the buffer
         private int _end;                 // end position of the buffer
         private uint _bitBuffer = 0;      // store the bits here, we can quickly shift in this buffer
@@ -44,6 +44,7 @@ namespace System.IO.Compression
                 {
                     return false;
                 }
+                Debug.Assert(_buffer != null);
                 // insert a byte to bitbuffer
                 _bitBuffer |= (uint)_buffer[_start++] << _bitsInBuffer;
                 _bitsInBuffer += 8;
@@ -72,6 +73,7 @@ namespace System.IO.Compression
         /// </summary>
         public uint TryLoad16Bits()
         {
+            Debug.Assert(_buffer != null);
             if (_bitsInBuffer < 8)
             {
                 if (_start < _end)
@@ -152,6 +154,7 @@ namespace System.IO.Compression
                 length = avail;
             }
 
+            Debug.Assert(_buffer != null);
             Array.Copy(_buffer, _start, output, offset, length);
             _start += length;
             return bytesFromBitBuffer + length;
index f09f827..9416b37 100644 (file)
@@ -14,12 +14,12 @@ namespace System.IO.Compression
     {
         private const int DefaultBufferSize = 8192;
 
-        private Stream _stream;
+        private Stream _stream = null!; // field initialized in init methods called from constructor
         private CompressionMode _mode;
         private bool _leaveOpen;
-        private Inflater _inflater;
-        private Deflater _deflater;
-        private byte[] _buffer;
+        private Inflater? _inflater;
+        private Deflater? _deflater;
+        private byte[]? _buffer;
         private int _activeAsyncOperation; // 1 == true, 0 == false
         private bool _wroteBytes;
 
@@ -57,7 +57,13 @@ namespace System.IO.Compression
             switch (mode)
             {
                 case CompressionMode.Decompress:
-                    InitializeInflater(stream, leaveOpen, windowBits, uncompressedSize);
+                    if (!stream.CanRead)
+                        throw new ArgumentException(SR.NotSupported_UnreadableStream, nameof(stream));
+
+                    _inflater = new Inflater(windowBits, uncompressedSize);
+                    _stream = stream;
+                    _mode = CompressionMode.Decompress;
+                    _leaveOpen = leaveOpen;
                     break;
 
                 case CompressionMode.Compress:
@@ -81,22 +87,6 @@ namespace System.IO.Compression
         }
 
         /// <summary>
-        /// Sets up this DeflateStream to be used for Zlib Inflation/Decompression
-        /// </summary>
-        internal void InitializeInflater(Stream stream, bool leaveOpen, int windowBits, long uncompressedSize)
-        {
-            Debug.Assert(stream != null);
-            if (!stream.CanRead)
-                throw new ArgumentException(SR.NotSupported_UnreadableStream, nameof(stream));
-
-            _inflater = new Inflater(windowBits, uncompressedSize);
-
-            _stream = stream;
-            _mode = CompressionMode.Decompress;
-            _leaveOpen = leaveOpen;
-        }
-
-        /// <summary>
         /// Sets up this DeflateStream to be used for Zlib Deflation/Compression
         /// </summary>
         internal void InitializeDeflater(Stream stream, bool leaveOpen, int windowBits, CompressionLevel compressionLevel)
@@ -191,6 +181,7 @@ namespace System.IO.Compression
             AsyncOperationStarting();
             try
             {
+                Debug.Assert(_deflater != null && _buffer != null);
                 // Compress any bytes left:
                 await WriteDeflaterOutputAsync(cancellationToken).ConfigureAwait(false);
 
@@ -231,6 +222,7 @@ namespace System.IO.Compression
             // Try to read a single byte from zlib without allocating an array, pinning an array, etc.
             // If zlib doesn't have any data, fall back to the base stream implementation, which will do that.
             byte b;
+            Debug.Assert(_inflater != null);
             return _inflater.Inflate(out b) ? b : base.ReadByte();
         }
 
@@ -263,6 +255,7 @@ namespace System.IO.Compression
 
             int totalRead = 0;
 
+            Debug.Assert(_inflater != null);
             while (true)
             {
                 int bytesRead = _inflater.Inflate(buffer.Slice(totalRead));
@@ -283,6 +276,7 @@ namespace System.IO.Compression
 
                 if (_inflater.NeedsInput())
                 {
+                    Debug.Assert(_buffer != null);
                     int bytes = _stream.Read(_buffer, 0, _buffer.Length);
                     if (bytes <= 0)
                     {
@@ -350,7 +344,7 @@ namespace System.IO.Compression
             throw new InvalidOperationException(SR.CannotWriteToDeflateStream);
         }
 
-        public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback asyncCallback, object asyncState) =>
+        public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? asyncCallback, object? asyncState) =>
             TaskToApm.Begin(ReadAsync(buffer, offset, count, CancellationToken.None), asyncCallback, asyncState);
 
         public override int EndRead(IAsyncResult asyncResult) =>
@@ -393,6 +387,7 @@ namespace System.IO.Compression
             AsyncOperationStarting();
             try
             {
+                Debug.Assert(_inflater != null);
                 while (true)
                 {
                     // Finish inflating any bytes in the input buffer
@@ -443,6 +438,7 @@ namespace System.IO.Compression
         {
             try
             {
+                Debug.Assert(_inflater != null && _buffer != null);
                 while (true)
                 {
                     if (_inflater.NeedsInput())
@@ -531,6 +527,7 @@ namespace System.IO.Compression
             EnsureCompressionMode();
             EnsureNotDisposed();
 
+            Debug.Assert(_deflater != null);
             // Write compressed the bytes we already passed to the deflater:
             WriteDeflaterOutput();
 
@@ -548,6 +545,7 @@ namespace System.IO.Compression
 
         private void WriteDeflaterOutput()
         {
+            Debug.Assert(_deflater != null && _buffer != null);
             while (!_deflater.NeedsInput())
             {
                 int compressedBytes = _deflater.GetDeflateOutput(_buffer);
@@ -567,6 +565,7 @@ namespace System.IO.Compression
                 // Compress any bytes left:
                 WriteDeflaterOutput();
 
+                Debug.Assert(_deflater != null && _buffer != null);
                 // Pull out any bytes left inside deflater:
                 bool flushSuccessful;
                 do
@@ -594,6 +593,7 @@ namespace System.IO.Compression
             if (_mode != CompressionMode.Compress)
                 return;
 
+            Debug.Assert(_deflater != null && _buffer != null);
             // Some deflaters (e.g. ZLib) write more than zero bytes for zero byte inputs.
             // This round-trips and we should be ok with this, but our legacy managed deflater
             // always wrote zero output for zero input and upstack code (e.g. ZipArchiveEntry)
@@ -641,6 +641,7 @@ namespace System.IO.Compression
             if (_mode != CompressionMode.Compress)
                 return;
 
+            Debug.Assert(_deflater != null && _buffer != null);
             // Some deflaters (e.g. ZLib) write more than zero bytes for zero byte inputs.
             // This round-trips and we should be ok with this, but our legacy managed deflater
             // always wrote zero output for zero input and upstack code (e.g. ZipArchiveEntry)
@@ -696,7 +697,7 @@ namespace System.IO.Compression
                 }
                 finally
                 {
-                    _stream = null;
+                    _stream = null!;
 
                     try
                     {
@@ -708,7 +709,7 @@ namespace System.IO.Compression
                         _deflater = null;
                         _inflater = null;
 
-                        byte[] buffer = _buffer;
+                        byte[]? buffer = _buffer;
                         if (buffer != null)
                         {
                             _buffer = null;
@@ -744,7 +745,7 @@ namespace System.IO.Compression
                 // Stream.Close() may throw here (may or may not be due to the same error).
                 // In this case, we still need to clean up internal resources, hence the inner finally blocks.
                 Stream stream = _stream;
-                _stream = null;
+                _stream = null!;
                 try
                 {
                     if (!_leaveOpen && stream != null)
@@ -762,7 +763,7 @@ namespace System.IO.Compression
                         _deflater = null;
                         _inflater = null;
 
-                        byte[] buffer = _buffer;
+                        byte[]? buffer = _buffer;
                         if (buffer != null)
                         {
                             _buffer = null;
@@ -776,7 +777,7 @@ namespace System.IO.Compression
             }
         }
 
-        public override IAsyncResult BeginWrite(byte[] array, int offset, int count, AsyncCallback asyncCallback, object asyncState) =>
+        public override IAsyncResult BeginWrite(byte[] array, int offset, int count, AsyncCallback? asyncCallback, object? asyncState) =>
             TaskToApm.Begin(WriteAsync(array, offset, count, CancellationToken.None), asyncCallback, asyncState);
 
         public override void EndWrite(IAsyncResult asyncResult) =>
@@ -820,6 +821,7 @@ namespace System.IO.Compression
             {
                 await WriteDeflaterOutputAsync(cancellationToken).ConfigureAwait(false);
 
+                Debug.Assert(_deflater != null);
                 // Pass new bytes through deflater
                 _deflater.SetInput(buffer);
 
@@ -838,6 +840,7 @@ namespace System.IO.Compression
         /// </summary>
         private async Task WriteDeflaterOutputAsync(CancellationToken cancellationToken)
         {
+            Debug.Assert(_deflater != null && _buffer != null);
             while (!_deflater.NeedsInput())
             {
                 int compressedBytes = _deflater.GetDeflateOutput(_buffer);
@@ -907,6 +910,7 @@ namespace System.IO.Compression
                 _deflateStream.AsyncOperationStarting();
                 try
                 {
+                    Debug.Assert(_deflateStream._inflater != null);
                     // Flush any existing data in the inflater to the destination stream.
                     while (!_deflateStream._inflater.Finished())
                     {
@@ -930,7 +934,7 @@ namespace System.IO.Compression
                     _deflateStream.AsyncOperationCompleting();
 
                     ArrayPool<byte>.Shared.Return(_arrayPoolBuffer);
-                    _arrayPoolBuffer = null;
+                    _arrayPoolBuffer = null!;
                 }
             }
 
@@ -938,6 +942,7 @@ namespace System.IO.Compression
             {
                 try
                 {
+                    Debug.Assert(_deflateStream._inflater != null);
                     // Flush any existing data in the inflater to the destination stream.
                     while (!_deflateStream._inflater.Finished())
                     {
@@ -959,7 +964,7 @@ namespace System.IO.Compression
                 finally
                 {
                     ArrayPool<byte>.Shared.Return(_arrayPoolBuffer);
-                    _arrayPoolBuffer = null;
+                    _arrayPoolBuffer = null!;
                 }
             }
 
@@ -979,6 +984,7 @@ namespace System.IO.Compression
                     throw new InvalidDataException(SR.GenericInvalidData);
                 }
 
+                Debug.Assert(_deflateStream._inflater != null);
                 // Feed the data from base stream into the decompression engine.
                 _deflateStream._inflater.SetInput(buffer, offset, count);
 
@@ -1015,6 +1021,7 @@ namespace System.IO.Compression
                     throw new InvalidDataException(SR.GenericInvalidData);
                 }
 
+                Debug.Assert(_deflateStream._inflater != null);
                 // Feed the data from base stream into the decompression engine.
                 _deflateStream._inflater.SetInput(buffer, offset, count);
 
index 4ad5a68..e7721dc 100644 (file)
@@ -16,7 +16,7 @@ namespace System.IO.Compression
     /// </summary>
     internal sealed class Deflater : IDisposable
     {
-        private ZLibNative.ZLibStreamHandle _zlibStream;
+        private readonly ZLibNative.ZLibStreamHandle _zlibStream;
         private MemoryHandle _inputBufferHandle;
         private bool _isDisposed;
         private const int minWindowBits = -15;  // WindowBits must be between -8..-15 to write no header, 8..15 for a
@@ -60,7 +60,34 @@ namespace System.IO.Compression
 
             ZLibNative.CompressionStrategy strategy = ZLibNative.CompressionStrategy.DefaultStrategy;
 
-            DeflateInit(zlibCompressionLevel, windowBits, memLevel, strategy);
+            ZErrorCode errC;
+            try
+            {
+                errC = ZLibNative.CreateZLibStreamForDeflate(out _zlibStream, zlibCompressionLevel,
+                                                             windowBits, memLevel, strategy);
+            }
+            catch (Exception cause)
+            {
+                throw new ZLibException(SR.ZLibErrorDLLLoadError, cause);
+            }
+
+            switch (errC)
+            {
+                case ZErrorCode.Ok:
+                    return;
+
+                case ZErrorCode.MemError:
+                    throw new ZLibException(SR.ZLibErrorNotEnoughMemory, "deflateInit2_", (int)errC, _zlibStream.GetErrorMessage());
+
+                case ZErrorCode.VersionError:
+                    throw new ZLibException(SR.ZLibErrorVersionMismatch, "deflateInit2_", (int)errC, _zlibStream.GetErrorMessage());
+
+                case ZErrorCode.StreamError:
+                    throw new ZLibException(SR.ZLibErrorIncorrectInitParameters, "deflateInit2_", (int)errC, _zlibStream.GetErrorMessage());
+
+                default:
+                    throw new ZLibException(SR.ZLibErrorUnexpected, "deflateInit2_", (int)errC, _zlibStream.GetErrorMessage());
+            }
         }
 
         ~Deflater()
@@ -198,39 +225,6 @@ namespace System.IO.Compression
             }
         }
 
-        private void DeflateInit(ZLibNative.CompressionLevel compressionLevel, int windowBits, int memLevel,
-                                 ZLibNative.CompressionStrategy strategy)
-        {
-            ZErrorCode errC;
-            try
-            {
-                errC = ZLibNative.CreateZLibStreamForDeflate(out _zlibStream, compressionLevel,
-                                                             windowBits, memLevel, strategy);
-            }
-            catch (Exception cause)
-            {
-                throw new ZLibException(SR.ZLibErrorDLLLoadError, cause);
-            }
-
-            switch (errC)
-            {
-                case ZErrorCode.Ok:
-                    return;
-
-                case ZErrorCode.MemError:
-                    throw new ZLibException(SR.ZLibErrorNotEnoughMemory, "deflateInit2_", (int)errC, _zlibStream.GetErrorMessage());
-
-                case ZErrorCode.VersionError:
-                    throw new ZLibException(SR.ZLibErrorVersionMismatch, "deflateInit2_", (int)errC, _zlibStream.GetErrorMessage());
-
-                case ZErrorCode.StreamError:
-                    throw new ZLibException(SR.ZLibErrorIncorrectInitParameters, "deflateInit2_", (int)errC, _zlibStream.GetErrorMessage());
-
-                default:
-                    throw new ZLibException(SR.ZLibErrorUnexpected, "deflateInit2_", (int)errC, _zlibStream.GetErrorMessage());
-            }
-        }
-
         private ZErrorCode Deflate(ZFlushCode flushCode)
         {
             ZErrorCode errC;
index 2c0a2be..78fcd17 100644 (file)
@@ -19,7 +19,7 @@ namespace System.IO.Compression
         private bool _finished;                             // Whether the end of the stream has been reached
         private bool _isDisposed;                           // Prevents multiple disposals
         private readonly int _windowBits;                            // The WindowBits parameter passed to Inflater construction
-        private ZLibNative.ZLibStreamHandle _zlibStream;    // The handle to the primary underlying zlib stream
+        private ZLibNative.ZLibStreamHandle _zlibStream = null!;    // The handle to the primary underlying zlib stream, initialized by a method that is called from the constructor
         private GCHandle _inputBufferHandle;                // The handle to the buffer that provides input to _zlibStream
         private readonly long _uncompressedSize;
         private long _currentInflatedCount;
index 1ee950b..660a3c4 100644 (file)
@@ -13,8 +13,8 @@ namespace System.IO.Compression
     [System.Runtime.CompilerServices.TypeForwardedFrom("System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
     public class ZLibException : IOException, ISerializable
     {
-        private readonly string _zlibErrorContext = string.Empty;
-        private readonly string _zlibErrorMessage = string.Empty;
+        private readonly string? _zlibErrorContext = string.Empty;
+        private readonly string? _zlibErrorMessage = string.Empty;
         private readonly ZLibNative.ErrorCode _zlibErrorCode = ZLibNative.ErrorCode.Ok;
 
         /// <summary>
@@ -25,7 +25,7 @@ namespace System.IO.Compression
         /// <param name="zlibErrorContext">A description of the context within zlib where the error occurred (e.g. the function name).</param>
         /// <param name="zlibErrorCode">The error code returned by a ZLib function that caused this exception.</param>
         /// <param name="zlibErrorMessage">The string provided by ZLib as error information (unlocalised).</param>
-        public ZLibException(string message, string zlibErrorContext, int zlibErrorCode, string zlibErrorMessage) : base(message)
+        public ZLibException(string? message, string? zlibErrorContext, int zlibErrorCode, string? zlibErrorMessage) : base(message)
         {
             _zlibErrorContext = zlibErrorContext;
             _zlibErrorCode = (ZLibNative.ErrorCode)zlibErrorCode;
@@ -46,7 +46,7 @@ namespace System.IO.Compression
         /// </summary>
         /// <param name="message">The error message that explains the reason for the exception.</param>
         /// <param name="innerException">The exception that is the cause of the current exception, or a <code>null</code>.</param>
-        public ZLibException(string message, Exception innerException) : base(message, innerException) { }
+        public ZLibException(string? message, Exception? innerException) : base(message, innerException) { }
 
         /// <summary>
         /// Initializes a new ZLibException with serialized data.
index 713f816..99e3ee7 100644 (file)
@@ -312,7 +312,7 @@ namespace System.IO.Compression
             }
 
             // This can work even after XxflateEnd().
-            public string GetErrorMessage() => _zStream.msg != ZNullPtr ? Marshal.PtrToStringAnsi(_zStream.msg) : string.Empty;
+            public string GetErrorMessage() => _zStream.msg != ZNullPtr ? Marshal.PtrToStringAnsi(_zStream.msg)! : string.Empty;
         }
 
         public static ErrorCode CreateZLibStreamForDeflate(out ZLibStreamHandle zLibStreamHandle, CompressionLevel level,
index e938bbd..00134ee 100644 (file)
@@ -72,7 +72,7 @@ namespace System.IO.Compression
             return _deflateStream.ReadByte();
         }
 
-        public override IAsyncResult BeginRead(byte[] array, int offset, int count, AsyncCallback asyncCallback, object asyncState) =>
+        public override IAsyncResult BeginRead(byte[] array, int offset, int count, AsyncCallback? asyncCallback, object? asyncState) =>
             TaskToApm.Begin(ReadAsync(array, offset, count, CancellationToken.None), asyncCallback, asyncState);
 
         public override int EndRead(IAsyncResult asyncResult) =>
@@ -100,7 +100,7 @@ namespace System.IO.Compression
             }
         }
 
-        public override IAsyncResult BeginWrite(byte[] array, int offset, int count, AsyncCallback asyncCallback, object asyncState) =>
+        public override IAsyncResult BeginWrite(byte[] array, int offset, int count, AsyncCallback? asyncCallback, object? asyncState) =>
             TaskToApm.Begin(WriteAsync(array, offset, count, CancellationToken.None), asyncCallback, asyncState);
 
         public override void EndWrite(IAsyncResult asyncResult) =>
@@ -142,7 +142,7 @@ namespace System.IO.Compression
                 {
                     _deflateStream.Dispose();
                 }
-                _deflateStream = null;
+                _deflateStream = null!;
             }
             finally
             {
@@ -157,17 +157,17 @@ namespace System.IO.Compression
                 return base.DisposeAsync();
             }
 
-            DeflateStream ds = _deflateStream;
+            DeflateStream? ds = _deflateStream;
             if (ds != null)
             {
-                _deflateStream = null;
+                _deflateStream = null!;
                 return ds.DisposeAsync();
             }
 
             return default;
         }
 
-        public Stream BaseStream => _deflateStream?.BaseStream;
+        public Stream BaseStream => _deflateStream?.BaseStream!;
 
         public override Task<int> ReadAsync(byte[] array, int offset, int count, CancellationToken cancellationToken)
         {
index 6daf909..8ca07e0 100644 (file)
@@ -36,7 +36,7 @@ namespace System.IO.Compression
             _stream.Write(buffer, offset, count);
         }
 
-        public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
+        public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object? state)
         {
             _position += count;
             return _stream.BeginWrite(buffer, offset, count, callback, state);
index 3d5a22e..a62b274 100644 (file)
@@ -14,9 +14,9 @@ namespace System.IO.Compression
 {
     public class ZipArchive : IDisposable
     {
-        private Stream _archiveStream;
-        private ZipArchiveEntry _archiveStreamOwner;
-        private BinaryReader _archiveReader;
+        private readonly Stream _archiveStream;
+        private ZipArchiveEntry? _archiveStreamOwner;
+        private BinaryReader? _archiveReader;
         private ZipArchiveMode _mode;
         private List<ZipArchiveEntry> _entries;
         private ReadOnlyCollection<ZipArchiveEntry> _entriesCollection;
@@ -27,9 +27,9 @@ namespace System.IO.Compression
         private bool _isDisposed;
         private uint _numberOfThisDisk; //only valid after ReadCentralDirectory
         private long _expectedNumberOfEntries;
-        private Stream _backingStream;
-        private byte[] _archiveComment;
-        private Encoding _entryNameEncoding;
+        private Stream? _backingStream;
+        private byte[]? _archiveComment;
+        private Encoding? _entryNameEncoding;
 
 #if DEBUG_FORCE_ZIP64
         public bool _forceZip64;
@@ -117,13 +117,99 @@ namespace System.IO.Compression
         ///     otherwise an <see cref="ArgumentException"/> is thrown.</para>
         /// </param>
         /// <exception cref="ArgumentException">If a Unicode encoding other than UTF-8 is specified for the <code>entryNameEncoding</code>.</exception>
-        public ZipArchive(Stream stream, ZipArchiveMode mode, bool leaveOpen, Encoding entryNameEncoding)
+        public ZipArchive(Stream stream, ZipArchiveMode mode, bool leaveOpen, Encoding? entryNameEncoding)
         {
             if (stream == null)
                 throw new ArgumentNullException(nameof(stream));
 
             EntryNameEncoding = entryNameEncoding;
-            Init(stream, mode, leaveOpen);
+            Stream? extraTempStream = null;
+
+            try
+            {
+                _backingStream = null;
+
+                // check stream against mode
+                switch (mode)
+                {
+                    case ZipArchiveMode.Create:
+                        if (!stream.CanWrite)
+                            throw new ArgumentException(SR.CreateModeCapabilities);
+                        break;
+                    case ZipArchiveMode.Read:
+                        if (!stream.CanRead)
+                            throw new ArgumentException(SR.ReadModeCapabilities);
+                        if (!stream.CanSeek)
+                        {
+                            _backingStream = stream;
+                            extraTempStream = stream = new MemoryStream();
+                            _backingStream.CopyTo(stream);
+                            stream.Seek(0, SeekOrigin.Begin);
+                        }
+                        break;
+                    case ZipArchiveMode.Update:
+                        if (!stream.CanRead || !stream.CanWrite || !stream.CanSeek)
+                            throw new ArgumentException(SR.UpdateModeCapabilities);
+                        break;
+                    default:
+                        // still have to throw this, because stream constructor doesn't do mode argument checks
+                        throw new ArgumentOutOfRangeException(nameof(mode));
+                }
+
+                _mode = mode;
+                if (mode == ZipArchiveMode.Create && !stream.CanSeek)
+                    _archiveStream = new PositionPreservingWriteOnlyStreamWrapper(stream);
+                else
+                    _archiveStream = stream;
+                _archiveStreamOwner = null;
+                if (mode == ZipArchiveMode.Create)
+                    _archiveReader = null;
+                else
+                    _archiveReader = new BinaryReader(_archiveStream);
+                _entries = new List<ZipArchiveEntry>();
+                _entriesCollection = new ReadOnlyCollection<ZipArchiveEntry>(_entries);
+                _entriesDictionary = new Dictionary<string, ZipArchiveEntry>();
+                _readEntries = false;
+                _leaveOpen = leaveOpen;
+                _centralDirectoryStart = 0; // invalid until ReadCentralDirectory
+                _isDisposed = false;
+                _numberOfThisDisk = 0; // invalid until ReadCentralDirectory
+                _archiveComment = null;
+
+                switch (mode)
+                {
+                    case ZipArchiveMode.Create:
+                        _readEntries = true;
+                        break;
+                    case ZipArchiveMode.Read:
+                        ReadEndOfCentralDirectory();
+                        break;
+                    case ZipArchiveMode.Update:
+                    default:
+                        Debug.Assert(mode == ZipArchiveMode.Update);
+                        if (_archiveStream.Length == 0)
+                        {
+                            _readEntries = true;
+                        }
+                        else
+                        {
+                            ReadEndOfCentralDirectory();
+                            EnsureCentralDirectoryRead();
+                            foreach (ZipArchiveEntry entry in _entries)
+                            {
+                                entry.ThrowIfNotOpenable(needToUncompress: false, needToLoadIntoMemory: true);
+                            }
+                        }
+                        break;
+                }
+            }
+            catch
+            {
+                if (extraTempStream != null)
+                    extraTempStream.Dispose();
+
+                throw;
+            }
         }
 
         /// <summary>
@@ -241,7 +327,7 @@ namespace System.IO.Compression
         /// <exception cref="InvalidDataException">The Zip archive is corrupt and the entries cannot be retrieved.</exception>
         /// <param name="entryName">A path relative to the root of the archive, identifying the desired entry.</param>
         /// <returns>A wrapper for the file entry in the archive. If no entry in the archive exists with the specified name, null will be returned.</returns>
-        public ZipArchiveEntry GetEntry(string entryName)
+        public ZipArchiveEntry? GetEntry(string entryName)
         {
             if (entryName == null)
                 throw new ArgumentNullException(nameof(entryName));
@@ -250,18 +336,17 @@ namespace System.IO.Compression
                 throw new NotSupportedException(SR.EntriesInCreateMode);
 
             EnsureCentralDirectoryRead();
-            ZipArchiveEntry result;
-            _entriesDictionary.TryGetValue(entryName, out result);
+            _entriesDictionary.TryGetValue(entryName, out ZipArchiveEntry? result);
             return result;
         }
 
-        internal BinaryReader ArchiveReader => _archiveReader;
+        internal BinaryReader? ArchiveReader => _archiveReader;
 
         internal Stream ArchiveStream => _archiveStream;
 
         internal uint NumberOfThisDisk => _numberOfThisDisk;
 
-        internal Encoding EntryNameEncoding
+        internal Encoding? EntryNameEncoding
         {
             get { return _entryNameEncoding; }
 
@@ -402,97 +487,6 @@ namespace System.IO.Compression
             }
         }
 
-        private void Init(Stream stream, ZipArchiveMode mode, bool leaveOpen)
-        {
-            Stream extraTempStream = null;
-
-            try
-            {
-                _backingStream = null;
-
-                // check stream against mode
-                switch (mode)
-                {
-                    case ZipArchiveMode.Create:
-                        if (!stream.CanWrite)
-                            throw new ArgumentException(SR.CreateModeCapabilities);
-                        break;
-                    case ZipArchiveMode.Read:
-                        if (!stream.CanRead)
-                            throw new ArgumentException(SR.ReadModeCapabilities);
-                        if (!stream.CanSeek)
-                        {
-                            _backingStream = stream;
-                            extraTempStream = stream = new MemoryStream();
-                            _backingStream.CopyTo(stream);
-                            stream.Seek(0, SeekOrigin.Begin);
-                        }
-                        break;
-                    case ZipArchiveMode.Update:
-                        if (!stream.CanRead || !stream.CanWrite || !stream.CanSeek)
-                            throw new ArgumentException(SR.UpdateModeCapabilities);
-                        break;
-                    default:
-                        // still have to throw this, because stream constructor doesn't do mode argument checks
-                        throw new ArgumentOutOfRangeException(nameof(mode));
-                }
-
-                _mode = mode;
-                if (mode == ZipArchiveMode.Create && !stream.CanSeek)
-                    _archiveStream = new PositionPreservingWriteOnlyStreamWrapper(stream);
-                else
-                    _archiveStream = stream;
-                _archiveStreamOwner = null;
-                if (mode == ZipArchiveMode.Create)
-                    _archiveReader = null;
-                else
-                    _archiveReader = new BinaryReader(_archiveStream);
-                _entries = new List<ZipArchiveEntry>();
-                _entriesCollection = new ReadOnlyCollection<ZipArchiveEntry>(_entries);
-                _entriesDictionary = new Dictionary<string, ZipArchiveEntry>();
-                _readEntries = false;
-                _leaveOpen = leaveOpen;
-                _centralDirectoryStart = 0; // invalid until ReadCentralDirectory
-                _isDisposed = false;
-                _numberOfThisDisk = 0; // invalid until ReadCentralDirectory
-                _archiveComment = null;
-
-                switch (mode)
-                {
-                    case ZipArchiveMode.Create:
-                        _readEntries = true;
-                        break;
-                    case ZipArchiveMode.Read:
-                        ReadEndOfCentralDirectory();
-                        break;
-                    case ZipArchiveMode.Update:
-                    default:
-                        Debug.Assert(mode == ZipArchiveMode.Update);
-                        if (_archiveStream.Length == 0)
-                        {
-                            _readEntries = true;
-                        }
-                        else
-                        {
-                            ReadEndOfCentralDirectory();
-                            EnsureCentralDirectoryRead();
-                            foreach (ZipArchiveEntry entry in _entries)
-                            {
-                                entry.ThrowIfNotOpenable(needToUncompress: false, needToLoadIntoMemory: true);
-                            }
-                        }
-                        break;
-                }
-            }
-            catch
-            {
-                if (extraTempStream != null)
-                    extraTempStream.Dispose();
-
-                throw;
-            }
-        }
-
         private void ReadCentralDirectory()
         {
             try
@@ -503,6 +497,7 @@ namespace System.IO.Compression
 
                 long numberOfEntries = 0;
 
+                Debug.Assert(_archiveReader != null);
                 //read the central directory
                 ZipCentralDirectoryFileHeader currentHeader;
                 bool saveExtraFieldsAndComments = Mode == ZipArchiveMode.Update;
@@ -537,6 +532,7 @@ namespace System.IO.Compression
 
                 long eocdStart = _archiveStream.Position;
 
+                Debug.Assert(_archiveReader != null);
                 // read the EOCD
                 ZipEndOfCentralDirectoryBlock eocd;
                 bool eocdProper = ZipEndOfCentralDirectoryBlock.TryReadBlock(_archiveReader, out eocd);
index cefa7ab..122a98f 100644 (file)
@@ -31,18 +31,18 @@ namespace System.IO.Compression
         private long? _storedOffsetOfCompressedData;
         private uint _crc32;
         // An array of buffers, each a maximum of MaxSingleBufferSize in size
-        private byte[][] _compressedBytes;
-        private MemoryStream _storedUncompressedData;
+        private byte[][]? _compressedBytes;
+        private MemoryStream? _storedUncompressedData;
         private bool _currentlyOpenForWrite;
         private bool _everOpenedForWrite;
-        private Stream _outstandingWriteStream;
+        private Stream? _outstandingWriteStream;
         private uint _externalFileAttr;
-        private string _storedEntryName;
-        private byte[] _storedEntryNameBytes;
+        private string _storedEntryName = null!;  // indirectly set in constructor using FullName property
+        private byte[] _storedEntryNameBytes = null!;
         // only apply to update mode
-        private List<ZipGenericExtraField> _cdUnknownExtraFields;
-        private List<ZipGenericExtraField> _lhUnknownExtraFields;
-        private readonly byte[] _fileComment;
+        private List<ZipGenericExtraField>? _cdUnknownExtraFields;
+        private List<ZipGenericExtraField>? _lhUnknownExtraFields;
+        private readonly byte[]? _fileComment;
         private readonly CompressionLevel? _compressionLevel;
 
         // Initializes, attaches it to archive
@@ -274,7 +274,7 @@ namespace System.IO.Compression
             _archive.ThrowIfDisposed();
 
             _archive.RemoveEntry(this);
-            _archive = null;
+            _archive = null!;
             UnloadStreams();
         }
 
@@ -324,6 +324,7 @@ namespace System.IO.Compression
             {
                 if (_storedOffsetOfCompressedData == null)
                 {
+                    Debug.Assert(_archive.ArchiveReader != null);
                     _archive.ArchiveStream.Seek(_offsetOfLocalHeader, SeekOrigin.Begin);
                     // by calling this, we are using local header _storedEntryNameBytes.Length and extraFieldLength
                     // to find start of data, but still using central directory size information
@@ -553,15 +554,15 @@ namespace System.IO.Compression
         // can throw InvalidDataException
         internal bool LoadLocalHeaderExtraFieldAndCompressedBytesIfNeeded()
         {
-            string message;
             // we should have made this exact call in _archive.Init through ThrowIfOpenable
-            Debug.Assert(IsOpenable(false, true, out message));
+            Debug.Assert(IsOpenable(false, true, out string? message));
 
             // load local header's extra fields. it will be null if we couldn't read for some reason
             if (_originallyInArchive)
             {
                 _archive.ArchiveStream.Seek(_offsetOfLocalHeader, SeekOrigin.Begin);
 
+                Debug.Assert(_archive.ArchiveReader != null);
                 _lhUnknownExtraFields = ZipLocalFileHeader.GetExtraFields(_archive.ArchiveReader);
             }
 
@@ -590,12 +591,11 @@ namespace System.IO.Compression
 
         internal void ThrowIfNotOpenable(bool needToUncompress, bool needToLoadIntoMemory)
         {
-            string message;
-            if (!IsOpenable(needToUncompress, needToLoadIntoMemory, out message))
+            if (!IsOpenable(needToUncompress, needToLoadIntoMemory, out string? message))
                 throw new InvalidDataException(message);
         }
 
-        private CheckSumAndSizeWriteStream GetDataCompressor(Stream backingStream, bool leaveBackingStreamOpen, EventHandler onClose)
+        private CheckSumAndSizeWriteStream GetDataCompressor(Stream backingStream, bool leaveBackingStreamOpen, EventHandler? onClose)
         {
             // stream stack: backingStream -> DeflateStream -> CheckSumWriteStream
 
@@ -627,7 +627,7 @@ namespace System.IO.Compression
                 leaveCompressorStreamOpenOnClose,
                 this,
                 onClose,
-                (long initialPosition, long currentPosition, uint checkSum, Stream backing, ZipArchiveEntry thisRef, EventHandler closeHandler) =>
+                (long initialPosition, long currentPosition, uint checkSum, Stream backing, ZipArchiveEntry thisRef, EventHandler? closeHandler) =>
                 {
                     thisRef._crc32 = checkSum;
                     thisRef._uncompressedSize = currentPosition;
@@ -640,7 +640,7 @@ namespace System.IO.Compression
 
         private Stream GetDataDecompressor(Stream compressedStreamToRead)
         {
-            Stream uncompressedStream = null;
+            Stream? uncompressedStream = null;
             switch (CompressionMethod)
             {
                 case CompressionMethodValues.Deflate:
@@ -680,10 +680,10 @@ namespace System.IO.Compression
             _archive.DebugAssertIsStillArchiveStreamOwner(this);
 
             _everOpenedForWrite = true;
-            CheckSumAndSizeWriteStream crcSizeStream = GetDataCompressor(_archive.ArchiveStream, true, (object o, EventArgs e) =>
+            CheckSumAndSizeWriteStream crcSizeStream = GetDataCompressor(_archive.ArchiveStream, true, (object? o, EventArgs e) =>
             {
                 // release the archive stream
-                var entry = (ZipArchiveEntry)o;
+                var entry = (ZipArchiveEntry)o!;
                 entry._archive.ReleaseArchiveStream(entry);
                 entry._outstandingWriteStream = null;
             });
@@ -709,11 +709,11 @@ namespace System.IO.Compression
                 // so we don't fill in any size information
                 // those fields get figured out when we call GetCompressor as we write it to
                 // the actual archive
-                thisRef._currentlyOpenForWrite = false;
+                thisRef!._currentlyOpenForWrite = false;
             });
         }
 
-        private bool IsOpenable(bool needToUncompress, bool needToLoadIntoMemory, out string message)
+        private bool IsOpenable(bool needToUncompress, bool needToLoadIntoMemory, out string? message)
         {
             message = null;
 
@@ -748,6 +748,7 @@ namespace System.IO.Compression
                     message = SR.LocalFileHeaderCorrupt;
                     return false;
                 }
+                Debug.Assert(_archive.ArchiveReader != null);
                 _archive.ArchiveStream.Seek(_offsetOfLocalHeader, SeekOrigin.Begin);
                 if (needToUncompress && !needToLoadIntoMemory)
                 {
@@ -932,6 +933,7 @@ namespace System.IO.Compression
                     // according to ZIP specs, zero-byte files MUST NOT include file data
                     if (_uncompressedSize != 0)
                     {
+                        Debug.Assert(_compressedBytes != null);
                         foreach (byte[] compressedBytes in _compressedBytes)
                         {
                             _archive.ArchiveStream.Write(compressedBytes, 0, compressedBytes.Length);
index 9f40670..bad189c 100644 (file)
@@ -185,7 +185,7 @@ namespace System.IO.Compression
                 return false;
 
             // this pattern needed because nested using blocks trigger CA2202
-            MemoryStream ms = null;
+            MemoryStream? ms = null;
             try
             {
                 ms = new MemoryStream(extraField.Data);
@@ -555,8 +555,8 @@ namespace System.IO.Compression
         public long RelativeOffsetOfLocalHeader;
 
         public byte[] Filename;
-        public byte[] FileComment;
-        public List<ZipGenericExtraField> ExtraFields;
+        public byte[]? FileComment;
+        public List<ZipGenericExtraField>? ExtraFields;
 
         // if saveExtraFieldsAndComments is false, FileComment and ExtraFields will be null
         // in either case, the zip64 extra field info will be incorporated into other fields
@@ -653,7 +653,7 @@ namespace System.IO.Compression
         public uint OffsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber;
         public byte[] ArchiveComment;
 
-        public static void WriteBlock(Stream stream, long numberOfEntries, long startOfCentralDirectory, long sizeOfCentralDirectory, byte[] archiveComment)
+        public static void WriteBlock(Stream stream, long numberOfEntries, long startOfCentralDirectory, long sizeOfCentralDirectory, byte[]? archiveComment)
         {
             BinaryWriter writer = new BinaryWriter(stream);
 
index 129f787..17d3b25 100644 (file)
@@ -12,16 +12,16 @@ namespace System.IO.Compression
         private readonly bool _closeBaseStream;
 
         // Delegate that will be invoked on stream disposing
-        private readonly Action<ZipArchiveEntry> _onClosed;
+        private readonly Action<ZipArchiveEntry?>? _onClosed;
 
         // Instance that will be passed to _onClose delegate
-        private readonly ZipArchiveEntry _zipArchiveEntry;
+        private readonly ZipArchiveEntry? _zipArchiveEntry;
         private bool _isDisposed;
 
         internal WrappedStream(Stream baseStream, bool closeBaseStream)
             : this(baseStream, closeBaseStream, null, null) { }
 
-        private WrappedStream(Stream baseStream, bool closeBaseStream, ZipArchiveEntry entry, Action<ZipArchiveEntry> onClosed)
+        private WrappedStream(Stream baseStream, bool closeBaseStream, ZipArchiveEntry? entry, Action<ZipArchiveEntry?>? onClosed)
         {
             _baseStream = baseStream;
             _closeBaseStream = closeBaseStream;
@@ -30,7 +30,7 @@ namespace System.IO.Compression
             _isDisposed = false;
         }
 
-        internal WrappedStream(Stream baseStream, ZipArchiveEntry entry, Action<ZipArchiveEntry> onClosed)
+        internal WrappedStream(Stream baseStream, ZipArchiveEntry entry, Action<ZipArchiveEntry?>? onClosed)
             : this(baseStream, false, entry, onClosed) { }
 
         public override long Length
@@ -282,10 +282,10 @@ namespace System.IO.Compression
         // this is the position in BaseBaseStream
         private long _initialPosition;
         private readonly ZipArchiveEntry _zipArchiveEntry;
-        private readonly EventHandler _onClose;
+        private readonly EventHandler? _onClose;
         // Called when the stream is closed.
         // parameters are initialPosition, currentPosition, checkSum, baseBaseStream, zipArchiveEntry and onClose handler
-        private readonly Action<long, long, uint, Stream, ZipArchiveEntry, EventHandler> _saveCrcAndSizes;
+        private readonly Action<long, long, uint, Stream, ZipArchiveEntry, EventHandler?> _saveCrcAndSizes;
 
         // parameters to saveCrcAndSizes are
         // initialPosition (initialPosition in baseBaseStream),
@@ -295,8 +295,8 @@ namespace System.IO.Compression
         // zipArchiveEntry passed here so as to avoid closure allocation,
         // onClose handler passed here so as to avoid closure allocation
         public CheckSumAndSizeWriteStream(Stream baseStream, Stream baseBaseStream, bool leaveOpenOnClose,
-            ZipArchiveEntry entry, EventHandler onClose,
-            Action<long, long, uint, Stream, ZipArchiveEntry, EventHandler> saveCrcAndSizes)
+            ZipArchiveEntry entry, EventHandler? onClose,
+            Action<long, long, uint, Stream, ZipArchiveEntry, EventHandler?> saveCrcAndSizes)
         {
             _baseStream = baseStream;
             _baseBaseStream = baseBaseStream;