< 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
0%
Covered lines: 0
Uncovered lines: 159
Coverable lines: 159
Total lines: 432
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 27
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.cctor()100%110%
.ctor()100%110%
CreateForDeflate(...)100%110%
CreateForInflate(...)100%110%
ReleaseHandle()0%550%
EnsureState(...)0%220%
EnsureNativeHandleInitialized(...)0%12120%
DeflateInit2_(...)100%110%
Deflate(...)0%220%
DeflateEnd()100%110%
InflateInit2_(...)100%110%
InflateReset2_(...)0%220%
Inflate(...)0%220%
InflateEnd()100%110%
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:
 022        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()
 0176                : base(new IntPtr(-1), true)
 0177            {
 0178                _initializationState = State.NotInitialized;
 0179                SetHandle(IntPtr.Zero);
 0180            }
 181
 182            public static ZLibStreamHandle CreateForDeflate(CompressionLevel level, int windowBits,
 183                int memLevel, CompressionStrategy strategy)
 0184            {
 0185                ZLibStreamHandle zLibStreamHandle = new ZLibStreamHandle();
 186
 187                try
 0188                {
 0189                    zLibStreamHandle.DeflateInit2_(level, windowBits, memLevel, strategy);
 0190                }
 0191                catch (Exception)
 0192                {
 0193                    zLibStreamHandle.Dispose();
 0194                    throw;
 195                }
 196
 0197                return zLibStreamHandle;
 0198            }
 199
 200            public static ZLibStreamHandle CreateForInflate(int windowBits)
 0201            {
 0202                ZLibStreamHandle zLibStreamHandle = new ZLibStreamHandle();
 203
 204                try
 0205                {
 0206                    zLibStreamHandle.InflateInit2_(windowBits);
 0207                }
 0208                catch (Exception)
 0209                {
 0210                    zLibStreamHandle.Dispose();
 0211                    throw;
 212                }
 213
 0214                return zLibStreamHandle;
 0215            }
 216
 217            public override bool IsInvalid
 218            {
 0219                get { return handle == new IntPtr(-1); }
 220            }
 221
 222            public State InitializationState
 223            {
 0224                get { return _initializationState; }
 225            }
 226
 227            protected override bool ReleaseHandle() =>
 0228                InitializationState switch
 0229                {
 0230                    State.NotInitialized => true,
 0231                    State.InitializedForDeflate => (DeflateEnd() == ErrorCode.Ok),
 0232                    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?
 0235                };
 236
 237            public IntPtr NextIn
 238            {
 0239                get { return _zStream.nextIn; }
 0240                set { _zStream.nextIn = value; }
 241            }
 242
 243            public uint AvailIn
 244            {
 0245                get { return _zStream.availIn; }
 0246                set { _zStream.availIn = value; }
 247            }
 248
 249            public IntPtr NextOut
 250            {
 251                get { return _zStream.nextOut; }
 0252                set { _zStream.nextOut = value; }
 253            }
 254
 255            public uint AvailOut
 256            {
 0257                get { return _zStream.availOut; }
 0258                set { _zStream.availOut = value; }
 259            }
 260
 261            private void EnsureState(State requiredState)
 0262            {
 0263                if (InitializationState != requiredState)
 0264                    throw new InvalidOperationException("InitializationState != " + requiredState.ToString());
 0265            }
 266
 267            private void EnsureNativeHandleInitialized(ErrorCode zlibErrorCode, string zlibErrorContext)
 0268            {
 0269                Debug.Assert(zlibErrorContext is "deflateInit2_" or "inflateInit2_");
 270
 0271                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                }
 0290            }
 291
 292            private unsafe void DeflateInit2_(CompressionLevel level, int windowBits, int memLevel, CompressionStrategy 
 0293            {
 0294                Debug.Assert(InitializationState == State.NotInitialized);
 295
 296                ErrorCode errC;
 297
 298                try
 0299                {
 0300                    fixed (ZStream* stream = &_zStream)
 0301                    {
 0302                        errC = Interop.ZLib.DeflateInit2_(stream, level, CompressionMethod.Deflated, windowBits, memLeve
 0303                    }
 0304                }
 0305                catch (Exception e) // Could not load the ZLib dll
 0306                {
 0307                    throw new ZLibException(SR.ZLibErrorDLLLoadError, e);
 308                }
 309
 0310                EnsureNativeHandleInitialized(errC, "deflateInit2_");
 0311                _initializationState = State.InitializedForDeflate;
 0312            }
 313
 314            public unsafe ErrorCode Deflate(FlushCode flush)
 0315            {
 0316                bool refAdded = false;
 317                try
 0318                {
 0319                    DangerousAddRef(ref refAdded);
 0320                    EnsureState(State.InitializedForDeflate);
 321
 0322                    fixed (ZStream* stream = &_zStream)
 0323                    {
 0324                        return Interop.ZLib.Deflate(stream, flush);
 325                    }
 326                }
 327                finally
 0328                {
 0329                    if (refAdded)
 0330                    {
 0331                        DangerousRelease();
 0332                    }
 0333                }
 0334            }
 335
 336            private unsafe ErrorCode DeflateEnd()
 0337            {
 0338                EnsureState(State.InitializedForDeflate);
 339
 0340                fixed (ZStream* stream = &_zStream)
 0341                {
 0342                    ErrorCode errC = Interop.ZLib.DeflateEnd(stream);
 0343                    _initializationState = State.Disposed;
 344
 0345                    return errC;
 346                }
 0347            }
 348
 349            private unsafe void InflateInit2_(int windowBits)
 0350            {
 0351                Debug.Assert(InitializationState == State.NotInitialized);
 352
 353                ErrorCode errC;
 354
 355                try
 0356                {
 0357                    fixed (ZStream* stream = &_zStream)
 0358                    {
 0359                        errC = Interop.ZLib.InflateInit2_(stream, windowBits);
 0360                    }
 0361                }
 0362                catch (Exception e) // Could not load the ZLib dll
 0363                {
 0364                    throw new ZLibException(SR.ZLibErrorDLLLoadError, e);
 365                }
 366
 0367                EnsureNativeHandleInitialized(errC, "inflateInit2_");
 0368                _initializationState = State.InitializedForInflate;
 0369            }
 370
 371            public unsafe ErrorCode InflateReset2_(int windowBits)
 0372            {
 0373                bool refAdded = false;
 374                try
 0375                {
 0376                    DangerousAddRef(ref refAdded);
 0377                    EnsureState(State.InitializedForInflate);
 378
 0379                    fixed (ZStream* stream = &_zStream)
 0380                    {
 0381                        return Interop.ZLib.InflateReset2_(stream, windowBits);
 382                    }
 383                }
 384                finally
 0385                {
 0386                    if (refAdded)
 0387                    {
 0388                        DangerousRelease();
 0389                    }
 0390                }
 0391            }
 392
 393            public unsafe ErrorCode Inflate(FlushCode flush)
 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.Inflate(stream, flush);
 404                    }
 405                }
 406                finally
 0407                {
 0408                    if (refAdded)
 0409                    {
 0410                        DangerousRelease();
 0411                    }
 0412                }
 0413            }
 414
 415            private unsafe ErrorCode InflateEnd()
 0416            {
 0417                EnsureState(State.InitializedForInflate);
 418
 0419                fixed (ZStream* stream = &_zStream)
 0420                {
 0421                    ErrorCode errC = Interop.ZLib.InflateEnd(stream);
 0422                    _initializationState = State.Disposed;
 423
 0424                    return errC;
 425                }
 0426            }
 427
 428            // This can work even after XxflateEnd(). Gets the error message from the native library.
 0429            public unsafe string GetErrorMessage() => Utf8StringMarshaller.ConvertToManaged(_zStream.msg) ?? string.Empt
 430        }
 431    }
 432}