示例#1
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;
                }
            }
        }
示例#2
0
        private ZLibNative.ErrorCode Inflate(ZLibNative.FlushCode flushCode)
        {
            ZLibNative.ErrorCode errC;
            try
            {
                errC = _zlibStream.Inflate(flushCode);
            }
            catch (Exception cause) // could not load the Zlib DLL correctly
            {
                throw new ZLibException("SR.ZLibErrorDLLLoadError", cause);
            }
            switch (errC)
            {
                case ZLibNative.ErrorCode.Ok:           // progress has been made inflating
                case ZLibNative.ErrorCode.StreamEnd:    // The end of the input stream has been reached
                    return errC;

                case ZLibNative.ErrorCode.BufError:     // No room in the output buffer - inflate() can be called again with more space to continue
                    return errC;

                case ZLibNative.ErrorCode.MemError:     // Not enough memory to complete the operation
                    throw new ZLibException("SR.ZLibErrorNotEnoughMemory", "inflate_", (int)errC, _zlibStream.GetErrorMessage());

                case ZLibNative.ErrorCode.DataError:    // The input data was corrupted (input stream not conforming to the zlib format or incorrect check value)
                    throw new InvalidDataException("SR.UnsupportedCompression");

                case ZLibNative.ErrorCode.StreamError:  //the stream structure was inconsistent (for example if next_in or next_out was NULL),
                    throw new ZLibException("SR.ZLibErrorInconsistentStream", "inflate_", (int)errC, _zlibStream.GetErrorMessage());

                default:
                    throw new ZLibException("SR.ZLibErrorUnexpected", "inflate_", (int)errC, _zlibStream.GetErrorMessage());
            }
        }
示例#3
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;
                }
            }
        }
示例#4
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;
            }
        }