< Summary

Information
Class: System.IO.Compression.ZLibNative
Assembly: System.IO.Compression
File(s): D:\runner\runtime\src\libraries\Common\src\System\IO\Compression\ZLibNative.cs
Line coverage
62%
Covered lines: 108
Uncovered lines: 66
Coverable lines: 174
Total lines: 454
Line coverage: 62%
Branch coverage
37%
Covered branches: 11
Total branches: 29
Branch coverage: 37.9%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.cctor()100%11100%
.ctor()100%11100%
CreateForDeflate(...)100%1163.63%
CreateForInflate(...)100%1163.63%
ReleaseHandle()40%5562.5%
EnsureState(...)50%2275%
EnsureNativeHandleInitialized(...)33.33%121220%
DeflateInit2_(...)100%1178.57%
Deflate(...)100%22100%
DeflateReset()0%220%
DeflateEnd()100%11100%
InflateInit2_(...)100%1178.57%
InflateReset2_(...)0%220%
Inflate(...)100%22100%
InflateEnd()100%11100%
GetErrorMessage()0%220%

File(s)

D:\runner\runtime\src\libraries\Common\src\System\IO\Compression\ZLibNative.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Diagnostics;
 5using System.Runtime.InteropServices;
 6using System.Runtime.InteropServices.Marshalling;
 7using System.Security;
 8
 9namespace System.IO.Compression
 10{
 11    /// <summary>
 12    /// This class provides declaration for constants and PInvokes as well as some basic tools for exposing the
 13    /// native System.IO.Compression.Native.dll (effectively, ZLib) library to managed code.
 14    ///
 15    /// <para>See also: How to choose a compression level (in comments to <see cref="CompressionLevel" />.)</para>
 16    /// </summary>
 17    /// <seealso href="https://www.zlib.net/manual.html">ZLib manual</seealso>
 18    internal static partial class ZLibNative
 19    {
 20        // This is the NULL pointer for using with ZLib pointers;
 21        // we prefer it to IntPtr.Zero to mimic the definition of Z_NULL in zlib.h:
 122        internal static readonly IntPtr ZNullPtr = IntPtr.Zero;
 23
 24        public enum FlushCode : int
 25        {
 26            NoFlush = 0,
 27            SyncFlush = 2,
 28            Finish = 4,
 29            Block = 5
 30        }
 31
 32        public enum ErrorCode : int
 33        {
 34            Ok = 0,
 35            StreamEnd = 1,
 36            StreamError = -2,
 37            DataError = -3,
 38            MemError = -4,
 39            BufError = -5,
 40            VersionError = -6
 41        }
 42
 43        /// <summary>
 44        /// <para><strong>From the ZLib manual:</strong><br />
 45        /// <see cref="CompressionStrategy" /> is used to tune the compression algorithm.<br />
 46        /// Use the value <see cref="DefaultStrategy" /> for normal data, <see cref="Filtered" /> for data produced by a
 47        /// <see cref="HuffmanOnly" /> to force Huffman encoding only (no string match), or <see cref="RunLengthEncoding
 48        /// (run-length encoding). Filtered data consists mostly of small values with a somewhat random distribution. In
 49        /// compression algorithm is tuned to compress them better. The effect of <see cref="Filtered" /> is to force mo
 50        /// less string matching; it is somewhat intermediate between <see cref="DefaultStrategy" /> and <see cref="Huff
 51        /// <see cref="RunLengthEncoding" /> is designed to be almost as fast as <see cref="HuffmanOnly" />, but give be
 52        /// The strategy parameter only affects the compression ratio but not the correctness of the compressed output e
 53        /// appropriately. <see cref="Fixed" /> prevents the use of dynamic Huffman codes, allowing for a simpler decode
 54        ///
 55        /// <para><strong>For .NET Framework use:</strong><br />
 56        /// We have investigated compression scenarios for a bunch of different frequently occurring compression data an
 57        /// cases we investigated so far, <see cref="DefaultStrategy" /> provided best results</para>
 58        ///
 59        /// <para>See also: How to choose a compression level (in comments to <see cref="CompressionLevel" />.)</para>
 60        /// </summary>
 61        public enum CompressionStrategy : int
 62        {
 63            DefaultStrategy = 0,
 64            Filtered = 1,
 65            HuffmanOnly = 2,
 66            RunLengthEncoding = 3,
 67            Fixed = 4
 68        }
 69
 70        /// <summary>
 71        /// In version 2.2.1, zlib-ng provides only the <see cref="Deflated" /> <see cref="CompressionMethod" />.
 72        /// </summary>
 73        public enum CompressionMethod : int
 74        {
 75            Deflated = 8
 76        }
 77
 78        /// <summary>
 79        /// <para><strong>From the ZLib manual:</strong><br />
 80        /// ZLib's <c>windowBits</c> parameter is the base two logarithm of the window size (the size of the history buf
 81        /// It should be in the range 8..15 for this version of the library. Larger values of this parameter result in b
 82        /// at the expense of memory usage. The default value is 15 if <c>deflateInit</c> is used instead.</para>
 83        ///
 84        /// <para><strong>Note</strong>: <c>windowBits</c> can also be -8..-15 for raw deflate. In this case, -windowBit
 85        /// <c>Deflate</c> will then generate raw deflate data with no ZLib header or trailer, and will not compute an a
 86        ///
 87        /// <para>See also: How to choose a compression level (in comments to <see cref="CompressionLevel" />.)</para>
 88        /// </summary>
 89        public const int Deflate_DefaultWindowBits = -15; // Legal values are 8..15 and -8..-15. 15 is the window size,
 90                                                          // negative val causes deflate to produce raw deflate data (no
 91
 92        /// <summary>
 93        /// <para><strong>From the ZLib manual:</strong><br />
 94        /// ZLib's <c>windowBits</c> parameter is the base two logarithm of the window size (the size of the history buf
 95        /// It should be in the range 8..15 for this version of the library. Larger values of this parameter result in b
 96        /// at the expense of memory usage. The default value is 15 if <c>deflateInit</c> is used instead.</para>
 97        /// </summary>
 98        public const int ZLib_DefaultWindowBits = 15;
 99
 100        /// <summary>
 101        /// <para>ZLib's <c>windowBits</c> parameter is the base two logarithm of the window size (the size of the histo
 102        /// For GZip header encoding, <c>windowBits</c> should be equal to a value between 8..15 (to specify Window Size
 103        /// 16. The range of values for GZip encoding is therefore 24..31.</para>
 104        /// <para><strong>Note</strong>:<br />
 105        /// The GZip header will have no file name, no extra data, no comment, no modification time (set to zero), no he
 106        /// the operating system will be set based on the OS that the ZLib library was compiled to. <c>ZStream.adler</c>
 107        /// is a crc32 instead of an adler32.</para>
 108        /// </summary>
 109        public const int GZip_DefaultWindowBits = 31;
 110
 111        /// <summary>
 112        /// The minimum value for the base-2 logarithm of the history buffer (window) size.
 113        /// A value of 8 corresponds to a 256-byte window.
 114        /// </summary>
 115        public const int MinWindowLog = 8;
 116
 117        /// <summary>
 118        /// The maximum value for the base-2 logarithm of the history buffer (window) size.
 119        /// A value of 15 corresponds to a 32KB window, which provides the best compression ratio.
 120        /// </summary>
 121        public const int MaxWindowLog = 15;
 122
 123        /// <summary>
 124        /// The default value for the base-2 logarithm of the history buffer (window) size.
 125        /// Defaults to <see cref="MaxWindowLog"/> (15) for optimal compression.
 126        /// </summary>
 127        public const int DefaultWindowLog = MaxWindowLog;
 128
 129        /// <summary>
 130        /// The minimum compression quality level. A value of 0 means no compression (store only).
 131        /// </summary>
 132        public const int MinQuality = 0;
 133
 134        /// <summary>
 135        /// The maximum compression quality level. A value of 9 provides the best compression ratio
 136        /// but is the slowest.
 137        /// </summary>
 138        public const int MaxQuality = 9;
 139
 140        /// <summary>
 141        /// The default compression quality level. A value of 6 provides a good balance between
 142        /// compression ratio and speed.
 143        /// </summary>
 144        public const int DefaultQuality = 6;
 145
 146        /// <summary>
 147        /// <para><strong>From the ZLib manual:</strong><br />
 148        /// The <c>memLevel</c> parameter specifies how much memory should be allocated for the internal compression sta
 149        /// <c>memLevel</c> = 1 uses minimum memory but is slow and reduces compression ratio; <c>memLevel</c> = 9 uses 
 150        /// memory for optimal speed. The default value is 8.</para>
 151        ///
 152        /// <para>See also: How to choose a compression level (in comments to <see cref="CompressionLevel" />.)</para>
 153        /// </summary>
 154        public const int Deflate_DefaultMemLevel = 8;     // Memory usage by deflate. Legal range: [1..9]. 8 is ZLib def
 155                                                          // More is faster and better compression with more memory usag
 156        public const int Deflate_NoCompressionMemLevel = 7;
 157
 158        public const byte GZip_Header_ID1 = 31;
 159        public const byte GZip_Header_ID2 = 139;
 160
 161        public sealed class ZLibStreamHandle : SafeHandle
 162        {
 163            public enum State
 164            {
 165                NotInitialized,
 166                InitializedForDeflate,
 167                InitializedForInflate,
 168                Disposed
 169            }
 170
 171            private ZStream _zStream;
 172
 173            private volatile State _initializationState;
 174
 175            public ZLibStreamHandle()
 2997176                : base(new IntPtr(-1), true)
 2997177            {
 2997178                _initializationState = State.NotInitialized;
 2997179                SetHandle(IntPtr.Zero);
 2997180            }
 181
 182            public static ZLibStreamHandle CreateForDeflate(CompressionLevel level, int windowBits,
 183                int memLevel, CompressionStrategy strategy)
 1494184            {
 1494185                ZLibStreamHandle zLibStreamHandle = new ZLibStreamHandle();
 186
 187                try
 1494188                {
 1494189                    zLibStreamHandle.DeflateInit2_(level, windowBits, memLevel, strategy);
 1494190                }
 0191                catch (Exception)
 0192                {
 0193                    zLibStreamHandle.Dispose();
 0194                    throw;
 195                }
 196
 1494197                return zLibStreamHandle;
 1494198            }
 199
 200            public static ZLibStreamHandle CreateForInflate(int windowBits)
 1503201            {
 1503202                ZLibStreamHandle zLibStreamHandle = new ZLibStreamHandle();
 203
 204                try
 1503205                {
 1503206                    zLibStreamHandle.InflateInit2_(windowBits);
 1503207                }
 0208                catch (Exception)
 0209                {
 0210                    zLibStreamHandle.Dispose();
 0211                    throw;
 212                }
 213
 1503214                return zLibStreamHandle;
 1503215            }
 216
 217            public override bool IsInvalid
 218            {
 8991219                get { return handle == new IntPtr(-1); }
 220            }
 221
 222            public State InitializationState
 223            {
 44955224                get { return _initializationState; }
 225            }
 226
 227            protected override bool ReleaseHandle() =>
 2997228                InitializationState switch
 2997229                {
 0230                    State.NotInitialized => true,
 1494231                    State.InitializedForDeflate => (DeflateEnd() == ErrorCode.Ok),
 1503232                    State.InitializedForInflate => (InflateEnd() == ErrorCode.Ok),
 0233                    State.Disposed => true,
 0234                    _ => false,  // This should never happen. Did we forget one of the State enum values in the switch?
 2997235                };
 236
 237            public IntPtr NextIn
 238            {
 0239                get { return _zStream.nextIn; }
 17961240                set { _zStream.nextIn = value; }
 241            }
 242
 243            public uint AvailIn
 244            {
 61995245                get { return _zStream.availIn; }
 21849246                set { _zStream.availIn = value; }
 247            }
 248
 249            public IntPtr NextOut
 250            {
 251                get { return _zStream.nextOut; }
 17982252                set { _zStream.nextOut = value; }
 253            }
 254
 255            public uint AvailOut
 256            {
 17961257                get { return _zStream.availOut; }
 17982258                set { _zStream.availOut = value; }
 259            }
 260
 261            private void EnsureState(State requiredState)
 8991262            {
 8991263                if (InitializationState != requiredState)
 0264                    throw new InvalidOperationException("InitializationState != " + requiredState.ToString());
 8991265            }
 266
 267            private void EnsureNativeHandleInitialized(ErrorCode zlibErrorCode, string zlibErrorContext)
 2997268            {
 2997269                Debug.Assert(zlibErrorContext is "deflateInit2_" or "inflateInit2_");
 270
 2997271                if (zlibErrorCode is not ErrorCode.Ok)
 0272                {
 0273                    string zlibErrorMessage = GetErrorMessage();
 0274                    string exceptionMessage = zlibErrorCode switch
 0275                    {
 0276                        // Not enough memory
 0277                        ErrorCode.MemError => SR.ZLibErrorNotEnoughMemory,
 0278
 0279                        // zlib library is incompatible with the version assumed
 0280                        ErrorCode.VersionError => SR.ZLibErrorVersionMismatch,
 0281
 0282                        // Parameters are invalid
 0283                        ErrorCode.StreamError => SR.ZLibErrorIncorrectInitParameters,
 0284
 0285                        _ => SR.Format(SR.ZLibErrorUnexpected, (int)zlibErrorCode)
 0286                    };
 287
 0288                    throw new ZLibException(exceptionMessage, zlibErrorContext, (int)zlibErrorCode, zlibErrorMessage);
 289                }
 2997290            }
 291
 292            private unsafe void DeflateInit2_(CompressionLevel level, int windowBits, int memLevel, CompressionStrategy 
 1494293            {
 1494294                Debug.Assert(InitializationState == State.NotInitialized);
 295
 296                ErrorCode errC;
 297
 298                try
 1494299                {
 1494300                    fixed (ZStream* stream = &_zStream)
 1494301                    {
 1494302                        errC = Interop.ZLib.DeflateInit2_(stream, level, CompressionMethod.Deflated, windowBits, memLeve
 1494303                    }
 1494304                }
 0305                catch (Exception e) // Could not load the ZLib dll
 0306                {
 0307                    throw new ZLibException(SR.ZLibErrorDLLLoadError, e);
 308                }
 309
 1494310                EnsureNativeHandleInitialized(errC, "deflateInit2_");
 1494311                _initializationState = State.InitializedForDeflate;
 1494312            }
 313
 314            public unsafe ErrorCode Deflate(FlushCode flush)
 2988315            {
 2988316                bool refAdded = false;
 317                try
 2988318                {
 2988319                    DangerousAddRef(ref refAdded);
 2988320                    EnsureState(State.InitializedForDeflate);
 321
 2988322                    fixed (ZStream* stream = &_zStream)
 2988323                    {
 2988324                        return Interop.ZLib.Deflate(stream, flush);
 325                    }
 326                }
 327                finally
 2988328                {
 2988329                    if (refAdded)
 2988330                    {
 2988331                        DangerousRelease();
 2988332                    }
 2988333                }
 2988334            }
 335
 336            public unsafe ErrorCode DeflateReset()
 0337            {
 0338                bool refAdded = false;
 339                try
 0340                {
 0341                    DangerousAddRef(ref refAdded);
 0342                    EnsureState(State.InitializedForDeflate);
 343
 0344                    fixed (ZStream* stream = &_zStream)
 0345                    {
 0346                        return Interop.ZLib.DeflateReset(stream);
 347                    }
 348                }
 349                finally
 0350                {
 0351                    if (refAdded)
 0352                    {
 0353                        DangerousRelease();
 0354                    }
 0355                }
 0356            }
 357
 358            private unsafe ErrorCode DeflateEnd()
 1494359            {
 1494360                EnsureState(State.InitializedForDeflate);
 361
 1494362                fixed (ZStream* stream = &_zStream)
 1494363                {
 1494364                    ErrorCode errC = Interop.ZLib.DeflateEnd(stream);
 1494365                    _initializationState = State.Disposed;
 366
 1494367                    return errC;
 368                }
 1494369            }
 370
 371            private unsafe void InflateInit2_(int windowBits)
 1503372            {
 1503373                Debug.Assert(InitializationState == State.NotInitialized);
 374
 375                ErrorCode errC;
 376
 377                try
 1503378                {
 1503379                    fixed (ZStream* stream = &_zStream)
 1503380                    {
 1503381                        errC = Interop.ZLib.InflateInit2_(stream, windowBits);
 1503382                    }
 1503383                }
 0384                catch (Exception e) // Could not load the ZLib dll
 0385                {
 0386                    throw new ZLibException(SR.ZLibErrorDLLLoadError, e);
 387                }
 388
 1503389                EnsureNativeHandleInitialized(errC, "inflateInit2_");
 1503390                _initializationState = State.InitializedForInflate;
 1503391            }
 392
 393            public unsafe ErrorCode InflateReset2_(int windowBits)
 0394            {
 0395                bool refAdded = false;
 396                try
 0397                {
 0398                    DangerousAddRef(ref refAdded);
 0399                    EnsureState(State.InitializedForInflate);
 400
 0401                    fixed (ZStream* stream = &_zStream)
 0402                    {
 0403                        return Interop.ZLib.InflateReset2_(stream, windowBits);
 404                    }
 405                }
 406                finally
 0407                {
 0408                    if (refAdded)
 0409                    {
 0410                        DangerousRelease();
 0411                    }
 0412                }
 0413            }
 414
 415            public unsafe ErrorCode Inflate(FlushCode flush)
 3006416            {
 3006417                bool refAdded = false;
 418                try
 3006419                {
 3006420                    DangerousAddRef(ref refAdded);
 3006421                    EnsureState(State.InitializedForInflate);
 422
 3006423                    fixed (ZStream* stream = &_zStream)
 3006424                    {
 3006425                        return Interop.ZLib.Inflate(stream, flush);
 426                    }
 427                }
 428                finally
 3006429                {
 3006430                    if (refAdded)
 3006431                    {
 3006432                        DangerousRelease();
 3006433                    }
 3006434                }
 3006435            }
 436
 437            private unsafe ErrorCode InflateEnd()
 1503438            {
 1503439                EnsureState(State.InitializedForInflate);
 440
 1503441                fixed (ZStream* stream = &_zStream)
 1503442                {
 1503443                    ErrorCode errC = Interop.ZLib.InflateEnd(stream);
 1503444                    _initializationState = State.Disposed;
 445
 1503446                    return errC;
 447                }
 1503448            }
 449
 450            // This can work even after XxflateEnd(). Gets the error message from the native library.
 0451            public unsafe string GetErrorMessage() => Utf8StringMarshaller.ConvertToManaged(_zStream.msg) ?? string.Empt
 452        }
 453    }
 454}