Beispiel #1
0
        public int Inflate(byte[] bytes, int offset, int length)
        {
            Debug.Assert(null != bytes, "Can't pass in a null output buffer!");

            // If Inflate is called on an invalid or unready inflater, return 0 to indicate no bytes
            // have been read
            if (NeedsInput() || _inputBufferHandle == null || !_inputBufferHandle.IsAllocated || length == 0)
            {
                return(0);
            }

            // State is valid; attempt inflation
            try
            {
                int bytesRead;
                ZLibNative.ErrorCode errc = ReadInflateOutput(bytes, offset, length, ZLibNative.FlushCode.NoFlush, out bytesRead);
                if (errc == ZLibNative.ErrorCode.StreamEnd)
                {
                    _finished = true;
                }
                return(bytesRead);
            }
            finally
            {
                // Before returning, make sure to release input buffer if necesary:
                if (0 == _zlibStream.AvailIn && _inputBufferHandle.IsAllocated)
                {
                    DeallocateInputBufferHandle();
                }
            }
        }
        /// <summary>
        /// Initializes a new ZLibException with serialized data.
        /// </summary>
        /// <param name="info">The SerializationInfo that holds the serialized object data about the exception being thrown.</param>
        /// <param name="context">The StreamingContext that contains contextual information about the source or destination.</param>
        protected ZLibException(SerializationInfo info, StreamingContext context) :
            base(info, context)
        {
            string errContext = info.GetString("zlibErrorContext");

            ZLibNative.ErrorCode errCode = (ZLibNative.ErrorCode)info.GetInt32("zlibErrorCode");
            string errMessage            = info.GetString("zlibErrorMessage");

            Init(errContext, errCode, errMessage);
        }
Beispiel #3
0
        /// <summary>
        /// Wrapper around the ZLib inflate function, configuring the stream appropriately.
        /// </summary>
        private unsafe ZLibNative.ErrorCode ReadInflateOutput(IntPtr bufPtr, int length, ZLibNative.FlushCode flushCode, out int bytesRead)
        {
            lock (_syncLock)
            {
                _zlibStream.NextOut  = bufPtr;
                _zlibStream.AvailOut = (uint)length;

                ZLibNative.ErrorCode errC = Inflate(flushCode);
                bytesRead = length - (int)_zlibStream.AvailOut;

                return(errC);
            }
        }
Beispiel #4
0
        /// <summary>
        /// Throw exception based on ZLib error code
        /// </summary>
        /// <param name="retVal"></param>
        private static void ThrowIfZLibError(ZLibNative.ErrorCode retVal)
        {
            // switch does not support fall-through
            bool invalidOperation = false;
            bool corruption       = false;

            switch (retVal)
            {
            case ZLibNative.ErrorCode.Ok:
                return;

            case ZLibNative.ErrorCode.StreamEnd:
                invalidOperation = true; break;

            case ZLibNative.ErrorCode.NeedDictionary:
                corruption = true; break;

            case ZLibNative.ErrorCode.StreamError:
                corruption = true; break;

            case ZLibNative.ErrorCode.DataError:
                corruption = true; break;

            case ZLibNative.ErrorCode.MemError:
                throw new OutOfMemoryException();

            case ZLibNative.ErrorCode.BufError:
                invalidOperation = true; break;

            case ZLibNative.ErrorCode.VersionError:
                throw new InvalidOperationException(SR.Get(SRID.ZLibVersionError,
                                                           System.Text.Encoding.UTF8.GetString(ZLibVersion, 0, ZLibVersion.Length)));

            default:
            {
                // ErrorNo
                throw new IOException();
            }
            }

            if (invalidOperation)
            {
                throw new InvalidOperationException();
            }

            if (corruption)
            {
                throw new FileFormatException(SR.Get(SRID.CorruptStream));
            }
        }
Beispiel #5
0
        /// <summary>
        /// Translates the given byte array to a GCHandle so that it can be passed to the ZLib
        /// Inflate function, then returns the result of that call.
        /// </summary>
        private unsafe ZLibNative.ErrorCode ReadInflateOutput(byte[] outputBuffer, int offset, int length, ZLibNative.FlushCode flushCode, out int bytesRead)
        {
            lock (_syncLock)
            {
                fixed(byte *bufPtr = outputBuffer)
                {
                    _zlibStream.NextOut  = (IntPtr)bufPtr + offset;
                    _zlibStream.AvailOut = (uint)length;

                    ZLibNative.ErrorCode errC = Inflate(flushCode);
                    bytesRead = length - (int)_zlibStream.AvailOut;

                    return(errC);
                }
            }
        }
 /// <summary>
 /// This is the preferred constructor to use.
 /// The other constructors are provided for compliance to Fx design guidelines.
 /// </summary>
 /// <param name="message">A (localised) human readable error description.</param>
 /// <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)
 {
     _zlibErrorContext = zlibErrorContext;
     _zlibErrorCode    = (ZLibNative.ErrorCode)zlibErrorCode;
     _zlibErrorMessage = zlibErrorMessage;
 }
Beispiel #7
0
        //------------------------------------------------------
        //
        //  IDeflateTransform Interface
        //
        //------------------------------------------------------
        /// <summary>
        /// Decompress delegate - invoke ZLib in a manner consistent with RMA/Office
        /// </summary>
        /// <param name="source">stream to read from</param>
        /// <param name="sink">stream to write to</param>
        public void Decompress(Stream source, Stream sink)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }

            if (sink == null)
            {
                throw new ArgumentNullException("sink");
            }

            Invariant.Assert(source.CanRead);
            Invariant.Assert(sink.CanWrite, "Logic Error - Cannot decompress into a read-only stream");

            // remember this for later
            long storedPosition = -1;

            try
            {
                if (source.CanSeek)
                {
                    storedPosition  = source.Position;
                    source.Position = 0;
                }
                if (sink.CanSeek)
                {
                    sink.Position = 0;
                }

                // zlib state
                ZLibNative.ZLibStreamHandle zStream;

                // initialize the zlib library
                ZLibNative.ErrorCode retVal = ZLibNative.CreateZLibStreamForInflate(out zStream, DEFAULT_WINDOW_BITS);

                ThrowIfZLibError(retVal);

                byte[]   sourceBuf   = null;                // source buffer
                byte[]   sinkBuf     = null;                // destination buffer - where to write data
                GCHandle gcSourceBuf = new GCHandle();      // Preallocate these so we can safely access them
                GCHandle gcSinkBuf   = new GCHandle();      // in the next finally block.

                try
                {
                    // read all available data
                    // each block is preceded by a header that is 3 ulongs
                    int  uncompressedSize, compressedSize;
                    long destStreamLength = 0;      // keep track of decompressed size
                    while (ReadBlockHeader(source, out uncompressedSize, out compressedSize))
                    {
                        // ensure we have space
                        AllocOrRealloc(compressedSize, ref sourceBuf, ref gcSourceBuf);
                        AllocOrRealloc(uncompressedSize, ref sinkBuf, ref gcSinkBuf);

                        // read the data into the sourceBuf
                        int bytesRead = PackagingUtilities.ReliableRead(source, sourceBuf, 0, compressedSize);
                        if (bytesRead > 0)
                        {
                            if (compressedSize != bytesRead)
                            {
                                throw new FileFormatException(SR.Get(SRID.CorruptStream));
                            }

                            // prepare structure
                            // The buffer pointers must be reset for every call
                            // because ZLibNative.Inflate modifies them
                            zStream.NextIn   = gcSourceBuf.AddrOfPinnedObject();
                            zStream.NextOut  = gcSinkBuf.AddrOfPinnedObject();
                            zStream.AvailIn  = (uint)bytesRead;      // this is number of bytes available for decompression at pInBuf and is updated by ums_deflate call
                            zStream.AvailOut = (uint)sinkBuf.Length; // this is the number of bytes free in pOutBuf and is updated by ums_deflate call

                            // InvokeZLib does the actual interop.  It updates zStream, and sinkBuf (sourceBuf passed by ref to avoid copying)
                            // and leaves the decompressed data in sinkBuf.
                            //                        int decompressedSize = InvokeZLib(bytesRead, ref zStream, ref sourceBuf, ref sinkBuf, pSource, pSink, false);
                            retVal = zStream.Inflate(ZLibNative.FlushCode.SyncFlush);

                            ThrowIfZLibError(retVal);

                            checked
                            {
                                int decompressedSize = sinkBuf.Length - (int)zStream.AvailOut;

                                // verify that data matches header
                                if (decompressedSize != uncompressedSize)
                                {
                                    throw new FileFormatException(SR.Get(SRID.CorruptStream));
                                }

                                destStreamLength += decompressedSize;

                                // write to the base stream
                                sink.Write(sinkBuf, 0, decompressedSize);
                            }
                        }
                        else
                        {
                            // block header but no block data
                            if (compressedSize != 0)
                            {
                                throw new FileFormatException(SR.Get(SRID.CorruptStream));
                            }
                        }
                    }

                    // make sure we truncate if the destination stream was longer than this current decompress
                    if (sink.CanSeek)
                    {
                        sink.SetLength(destStreamLength);
                    }
                }
                finally
                {
                    if (gcSourceBuf.IsAllocated)
                    {
                        gcSourceBuf.Free();
                    }

                    if (gcSinkBuf.IsAllocated)
                    {
                        gcSinkBuf.Free();
                    }
                }
            }
            finally
            {
                // seek to the current logical position before returning
                if (source.CanSeek)
                {
                    source.Position = storedPosition;
                }
            }
        }
Beispiel #8
0
        /// <summary>
        /// Compress delegate - invoke ZLib in a manner consistent with RMA/Office
        /// </summary>
        /// <param name="source"></param>
        /// <param name="sink"></param>
        /// <remarks>We are careful to avoid use of Position, Length or SetLength on non-seekable streams.  If
        /// source or sink are non-seekable, it is assumed that positions are correctly set upon entry and that
        /// they need not be restored.  We also assume that destination stream length need not be truncated.</remarks>
        public void Compress(Stream source, Stream sink)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }

            if (sink == null)
            {
                throw new ArgumentNullException("sink");
            }

            Invariant.Assert(source.CanRead);
            Invariant.Assert(sink.CanWrite, "Logic Error - Cannot compress into a read-only stream");

            // remember this for later if possible
            long storedPosition = -1;       // default to illegal value to catch any logic errors

            try
            {
                int sourceBufferSize;   // don't allocate 4k for really tiny source streams
                if (source.CanSeek)
                {
                    storedPosition  = source.Position;
                    source.Position = 0;

                    // Casting result to int is safe because _defaultBlockSize is very small and the result
                    // of Math.Min(x, _defaultBlockSize) must be no larger than _defaultBlockSize.
                    sourceBufferSize = (int)(Math.Min(source.Length, (long)_defaultBlockSize));
                }
                else
                {
                    sourceBufferSize = _defaultBlockSize;    // can't call Length so fallback to default
                }
                if (sink.CanSeek)
                {
                    sink.Position = 0;
                }

                // zlib state
                ZLibNative.ZLibStreamHandle zStream;

                // initialize the zlib library
                ZLibNative.ErrorCode retVal = ZLibNative.CreateZLibStreamForDeflate(
                    out zStream,
                    ZLibNative.CompressionLevel.DefaultCompression,
                    DEFAULT_WINDOW_BITS,
                    DEFAULT_MEM_LEVEL,
                    ZLibNative.CompressionStrategy.DefaultStrategy);

                ThrowIfZLibError(retVal);

                // where to write data - can actually grow if data is uncompressible
                long     destStreamLength = 0;
                byte[]   sourceBuf        = null;   // source buffer
                byte[]   sinkBuf          = null;   // destination buffer
                GCHandle gcSourceBuf      = new GCHandle();
                GCHandle gcSinkBuf        = new GCHandle();
                try
                {
                    // allocate managed buffers
                    AllocOrRealloc(sourceBufferSize, ref sourceBuf, ref gcSourceBuf);
                    AllocOrRealloc(_defaultBlockSize + (_defaultBlockSize >> 1), ref sinkBuf, ref gcSinkBuf);

                    // while (more data is available)
                    //  - read into the sourceBuf
                    //  - compress into the sinkBuf
                    //  - emit the header
                    //  - write out to the _baseStream

                    // Suppress 6518 Local IDisposable object not disposed:
                    // Reason: The stream is not owned by us, therefore we cannot
                    // close the BinaryWriter as it will Close the stream underneath.
#pragma warning disable 6518
                    BinaryWriter writer = new BinaryWriter(sink);
                    int          bytesRead;
                    while ((bytesRead = PackagingUtilities.ReliableRead(source, sourceBuf, 0, sourceBuf.Length)) > 0)
                    {
                        Invariant.Assert(bytesRead <= sourceBufferSize);

                        // prepare structure
                        // these pointers must be re-assigned for each loop because
                        // ums_deflate modifies them
                        zStream.NextIn   = gcSourceBuf.AddrOfPinnedObject();
                        zStream.NextOut  = gcSinkBuf.AddrOfPinnedObject();
                        zStream.AvailIn  = (uint)bytesRead;        // this is number of bytes available for compression at pInBuf and is updated by ums_deflate call
                        zStream.AvailOut = (uint)sinkBuf.Length;   // this is the number of bytes free in pOutBuf and is updated by ums_deflate call

                        // cast is safe because SyncFlush is a constant
                        retVal = zStream.Deflate(ZLibNative.FlushCode.SyncFlush);
                        ThrowIfZLibError(retVal);

                        checked
                        {
                            int compressedSize = sinkBuf.Length - (int)zStream.AvailOut;
                            Invariant.Assert(compressedSize > 0, "compressing non-zero bytes creates a non-empty block");

                            // This should never happen because our destination buffer
                            // is twice as large as our source buffer
                            Invariant.Assert(zStream.AvailIn == 0, "Expecting all data to be compressed!");

                            // write the header
                            writer.Write(_blockHeaderToken);      // token
                            writer.Write((UInt32)bytesRead);
                            writer.Write((UInt32)compressedSize);
                            destStreamLength += _headerBuf.Length;

                            // write to the base stream
                            sink.Write(sinkBuf, 0, compressedSize);
                            destStreamLength += compressedSize;
                        }
                    }

                    // post-compression
                    // truncate if necessary
                    if (sink.CanSeek)
                    {
                        sink.SetLength(destStreamLength);
                    }
                }
                finally
                {
                    if (gcSourceBuf.IsAllocated)
                    {
                        gcSourceBuf.Free();
                    }

                    if (gcSinkBuf.IsAllocated)
                    {
                        gcSinkBuf.Free();
                    }
                }
#pragma warning restore 6518
            }
            finally
            {
                // seek to the current logical position before returning
                if (sink.CanSeek)
                {
                    source.Position = storedPosition;
                }
            }
        }