Пример #1
0
        /// <summary>
        /// 实现关闭流。
        /// </summary>
        protected virtual void CloseInternal()
        {
            if (_streamMode == StreamMode.Writer)
            {
                bool done = false;
                do
                {
                    _z.OutputBuffer      = WorkingBuffer;
                    _z.NextOut           = 0;
                    _z.AvailableBytesOut = _workingBuffer.Length;
                    ZlibState rc = (WantCompress)
                                                ? _z.Deflate(FlushType.Finish)
                                                : _z.Inflate(FlushType.Finish);
                    Thrower.ThrowZlibExceptionIf(rc != ZlibState.StreamEnd && rc != ZlibState.Success, (WantCompress ? "压缩" : "解压") + "错误" + (_z.Message == null ? ("状态 = " + Enum.GetName(typeof(ZlibState), rc)) : _z.Message));

                    if (_workingBuffer.Length - _z.AvailableBytesOut > 0)
                    {
                        _stream.Write(_workingBuffer, 0, _workingBuffer.Length - _z.AvailableBytesOut);
                    }

                    done = _z.AvailableBytesIn == 0 && _z.AvailableBytesOut != 0;
                    // If GZIP and de-compress, we're done when 8 bytes remain.
                    if (_isGZip && !WantCompress)
                    {
                        done = (_z.AvailableBytesIn == 8 && _z.AvailableBytesOut != 0);
                    }
                } while (!done);

                Flush();
            }
        }
Пример #2
0
        /// <summary>
        /// 停止处理。
        /// </summary>
        /// <returns>如果正常返回 ZlibState.Success 。</returns>
        public ZlibState EndInflate()
        {
            Thrower.ThrowZlibExceptionIf(IState == null, "没有初始化 Inflate 状态。");
            ZlibState ret = IState.End();

            IState = null;
            return(ret);
        }
Пример #3
0
        /// <summary>
        /// 向当前流中写入字节序列,并将此流中的当前位置提升写入的字节数。
        /// </summary>
        /// <param name="buffer">字节数组。此方法将 <paramref name="count"/> 个字节从 <paramref name="buffer"/> 复制到当前流。</param>
        /// <param name="offset"><paramref name="buffer"/> 中的从零开始的字节偏移量,从此处开始将字节复制到当前流。</param>
        /// <param name="count">要写入当前流的字节数。</param>
        /// <exception cref="T:System.ArgumentException">
        ///     <paramref name="offset"/> 与 <paramref name="count"/> 的和大于缓冲区长度。</exception>
        /// <exception cref="T:System.ArgumentNullException">
        ///     <paramref name="buffer"/> 为 null。</exception>
        /// <exception cref="T:System.ArgumentOutOfRangeException">
        ///     <paramref name="offset"/> 或 <paramref name="count"/> 为负。</exception>
        /// <exception cref="T:System.IO.IOException">发生 I/O 错误。</exception>
        /// <exception cref="T:System.NotSupportedException">流不支持写入。</exception>
        /// <exception cref="T:System.ObjectDisposedException">在流关闭后调用方法。</exception>
        public override void Write(byte[] buffer, int offset, int count)
        {
            Thrower.ThrowObjectDisposedExceptionIf(IsDisposed, TypeName);

            ValidStreamMode(StreamMode.Writer);

            if (count == 0)
            {
                return;
            }

            // first reference of z property will initialize the private var _z
            ZlibCodec.InputBuffer = buffer;
            _z.NextIn             = offset;
            _z.AvailableBytesIn   = count;
            bool done = false;

            do
            {
                _z.OutputBuffer      = WorkingBuffer;
                _z.NextOut           = 0;
                _z.AvailableBytesOut = _workingBuffer.Length;
                ZlibState rc = (WantCompress)
                    ? _z.Deflate(_flushMode)
                    : _z.Inflate(_flushMode);
                if (rc != ZlibState.Success && rc != ZlibState.StreamEnd)
                {
                    throw new ZlibException((WantCompress ? "压缩" : "解压") + "错误: " + _z.Message);
                }

                //if (_workingBuffer.Length - _z.AvailableBytesOut > 0)
                _stream.Write(_workingBuffer, 0, _workingBuffer.Length - _z.AvailableBytesOut);

                done = _z.AvailableBytesIn == 0 && _z.AvailableBytesOut != 0;

                // If GZIP and de-compress, we're done when 8 bytes remain.
                if (_isGZip && !WantCompress)
                {
                    done = (_z.AvailableBytesIn == 8 && _z.AvailableBytesOut != 0);
                }
            }   while (!done);
        }
Пример #4
0
 /// <summary>
 /// 初始化 <see cref="Py.Zip.Zlib.ZlibCodec"/> 的新实例。
 /// </summary>
 /// <param name="mode">指示当前操作是压缩或解压。</param>
 public ZlibCodec(CompressionMode mode)
 {
     if (mode == CompressionMode.Compress)
     {
         ZlibState rc = InitializeDeflate();
         if (rc != ZlibState.Success)
         {
             throw new ZlibException("无法初始化解压。");
         }
     }
     else if (mode == CompressionMode.Decompress)
     {
         ZlibState rc = InitializeInflate();
         if (rc != ZlibState.Success)
         {
             throw new ZlibException("无法初始化压缩。");
         }
     }
     else
     {
         throw new ZlibException("非法的模式。");
     }
 }
Пример #5
0
        private void IntermediateWrite(IAsyncResult asyncResult)
        {
            ZlibState state = (ZlibState)asyncResult.AsyncState;

            try
            {
                m_stream.EndWrite(asyncResult);
            }
            catch (Exception e)
            {
                ZlibStreamAsyncResult res = new ZlibStreamAsyncResult(state.state, e);
                state.callback(res);
                return;
            }

            m_out.next_out_index = 0;
            m_out.avail_out      = bufsize;
            int err = m_out.deflate(m_flush);

            if (err != zlibConst.Z_STREAM_END)
            {
                if (err != zlibConst.Z_OK)
                {
                    ZlibStreamAsyncResult res = new ZlibStreamAsyncResult(state.state, new CompressionFailedException("Compress failed: " + err));
                    state.callback(res);
                    return;
                }
            }
            if (m_out.avail_in == 0)
            {
                m_stream.BeginWrite(m_outbuf, 0, bufsize - m_out.avail_out, state.callback, state.state);
            }
            else
            {
                m_stream.BeginWrite(m_outbuf, 0, bufsize - m_out.avail_out, new AsyncCallback(IntermediateWrite), state);
            }
        }
Пример #6
0
        /// <summary>
        /// Performs the generic zlib stream filter operation.
        /// </summary>
        /// <param name="input">Input chunk of bytes.</param>
        /// <param name="inputOffset">Current position within the chunk.</param>
        /// <param name="closing">Value indicating whether the stream will be closed.</param>
        /// <returns>Array of available bytes (even empty one). Null on non-critical error.</returns>
        protected byte[] FilterInner(byte[] input, ref int inputOffset, bool closing)
        {
            if (_state == ZlibState.Finished)
            {
                //if stream already ended, throw an error
                PhpException.Throw(PhpError.Warning, "using zlib stream that is already finished");
                return null;
            }

            if (_state == ZlibState.Failed)
            {
                //if stream already ended, throw an error
                PhpException.Throw(PhpError.Warning, "using zlib stream that failed");
                return null;
            }

            List<Tuple<byte[], int>> subchunks = null;
            int status = zlibConst.Z_OK;

            // initialize if necessary
            if (_state == ZlibState.NotStarted)
            {
                _stream = new ZStream();

                // init algorithm
                status = InitZlibOperation(_stream);

                // check for error
                if (status != zlibConst.Z_OK)
                {
                    _state = ZlibState.Failed;
                    PhpException.Throw(PhpError.Error, Zlib.zError(status));
                    return null;
                }

                _state = ZlibState.Data;
            }

            if (_state == ZlibState.Data)
            {
                // input chunk
                _stream.next_in = input;
                _stream.next_in_index = inputOffset;
                _stream.avail_in = input.Length - inputOffset;

                long initial_total_out = _stream.total_out;
                long initial_total_in = _stream.total_in;

                int nextBufferSize = 8;
                int bufferSizeMax = 65536;

                // do while operation does some progress
                do
                {
                    _stream.next_out = new byte[nextBufferSize];
                    _stream.next_out_index = 0;
                    _stream.avail_out = _stream.next_out.Length;

                    if (nextBufferSize < bufferSizeMax)
                    {
                        nextBufferSize *= 2;
                    }

                    long previous_total_out = _stream.total_out;

                    status = PerformZlibOperation(_stream, GetFlushFlags(closing));

                    if (_stream.total_out - previous_total_out > 0)
                    {
                        // if the list was not initialize, do so
                        if (subchunks == null)
                            subchunks = new List<Tuple<byte[], int>>();

                        // add the subchunk to the list only when it contains some data
                        subchunks.Add(new Tuple<byte[], int>(_stream.next_out, (int)(_stream.total_out - previous_total_out)));
                    }
                }
                // we continue only when progress was made and there is input available
                while ((status == zlibConst.Z_OK || status == zlibConst.Z_BUF_ERROR) && (_stream.avail_in > 0 || (_stream.avail_in == 0 && _stream.avail_out == 0)));

                // if the last op wasn't the end of stream (this happens only with Z_FINISH) or general success, return error
                if (status != zlibConst.Z_STREAM_END && status != zlibConst.Z_OK)
                {
                    _state = ZlibState.Failed;
                    PhpException.Throw(PhpError.Warning, Zlib.zError(status));
                    return null;
                }

                // end the algorithm if requested
                if (closing || status == zlibConst.Z_STREAM_END)
                {
                    _state = ZlibState.Finished;

                    status = EndZlibOperation(_stream);

                    if (status != zlibConst.Z_OK)
                    {
                        _state = ZlibState.Failed;
                        PhpException.Throw(PhpError.Warning, Zlib.zError(status));
                        return null;
                    }
                }

                inputOffset = _stream.next_in_index;

                // if the chunk ended or everything is OK, connect the subchunks and return
                if (subchunks != null && subchunks.Count > 0)
                {
                    byte[] result = new byte[_stream.total_out - initial_total_out];
                    long resultPos = 0;

                    for (int i = 0; i < subchunks.Count; i++)
                    {
                        Buffer.BlockCopy(
                            subchunks[i].Item1,
                            0,
                            result,
                            (int)resultPos,
                            (int)Math.Min(subchunks[i].Item2, _stream.total_out - resultPos));

                        resultPos += subchunks[i].Item2;
                    }

                    return result;
                }
                else
                {
                    return new byte[0];
                }                
            }

            Debug.Fail();
            return null;
        }
Пример #7
0
 /// <summary>
 /// Initializes a new instance of the class.
 /// </summary>
 public ZlibFilter()
     : base(null)
 {
     _state = ZlibState.NotStarted;
 }
Пример #8
0
        /// <summary>
        /// Performs the generic zlib stream filter operation.
        /// </summary>
        /// <param name="input">Input chunk of bytes.</param>
        /// <param name="inputOffset">Current position within the chunk.</param>
        /// <param name="closing">Value indicating whether the stream will be closed.</param>
        /// <returns>Array of available bytes (even empty one). Null on non-critical error.</returns>
        protected byte[] FilterInner(byte[] input, ref int inputOffset, bool closing)
        {
            if (_state == ZlibState.Finished)
            {
                //if stream already ended, throw an error
                PhpException.Throw(PhpError.Warning, "using zlib stream that is already finished");
                return(null);
            }

            if (_state == ZlibState.Failed)
            {
                //if stream already ended, throw an error
                PhpException.Throw(PhpError.Warning, "using zlib stream that failed");
                return(null);
            }

            List <Tuple <byte[], int> > subchunks = null;
            int status = zlibConst.Z_OK;

            // initialize if necessary
            if (_state == ZlibState.NotStarted)
            {
                _stream = new ZStream();

                // init algorithm
                status = InitZlibOperation(_stream);

                // check for error
                if (status != zlibConst.Z_OK)
                {
                    _state = ZlibState.Failed;
                    PhpException.Throw(PhpError.Error, Zlib.zError(status));
                    return(null);
                }

                _state = ZlibState.Data;
            }

            if (_state == ZlibState.Data)
            {
                // input chunk
                _stream.next_in       = input;
                _stream.next_in_index = inputOffset;
                _stream.avail_in      = input.Length - inputOffset;

                long initial_total_out = _stream.total_out;
                long initial_total_in  = _stream.total_in;

                int nextBufferSize = 8;
                int bufferSizeMax  = 65536;

                // do while operation does some progress
                do
                {
                    _stream.next_out       = new byte[nextBufferSize];
                    _stream.next_out_index = 0;
                    _stream.avail_out      = _stream.next_out.Length;

                    if (nextBufferSize < bufferSizeMax)
                    {
                        nextBufferSize *= 2;
                    }

                    long previous_total_out = _stream.total_out;

                    status = PerformZlibOperation(_stream, GetFlushFlags(closing));

                    if (_stream.total_out - previous_total_out > 0)
                    {
                        // if the list was not initialize, do so
                        if (subchunks == null)
                        {
                            subchunks = new List <Tuple <byte[], int> >();
                        }

                        // add the subchunk to the list only when it contains some data
                        subchunks.Add(new Tuple <byte[], int>(_stream.next_out, (int)(_stream.total_out - previous_total_out)));
                    }
                }
                // we continue only when progress was made and there is input available
                while ((status == zlibConst.Z_OK || status == zlibConst.Z_BUF_ERROR) && (_stream.avail_in > 0 || (_stream.avail_in == 0 && _stream.avail_out == 0)));

                // if the last op wasn't the end of stream (this happens only with Z_FINISH) or general success, return error
                if (status != zlibConst.Z_STREAM_END && status != zlibConst.Z_OK)
                {
                    _state = ZlibState.Failed;
                    PhpException.Throw(PhpError.Warning, Zlib.zError(status));
                    return(null);
                }

                // end the algorithm if requested
                if (closing || status == zlibConst.Z_STREAM_END)
                {
                    _state = ZlibState.Finished;

                    status = EndZlibOperation(_stream);

                    if (status != zlibConst.Z_OK)
                    {
                        _state = ZlibState.Failed;
                        PhpException.Throw(PhpError.Warning, Zlib.zError(status));
                        return(null);
                    }
                }

                inputOffset = _stream.next_in_index;

                // if the chunk ended or everything is OK, connect the subchunks and return
                if (subchunks != null && subchunks.Count > 0)
                {
                    byte[] result    = new byte[_stream.total_out - initial_total_out];
                    long   resultPos = 0;

                    for (int i = 0; i < subchunks.Count; i++)
                    {
                        Buffer.BlockCopy(
                            subchunks[i].Item1,
                            0,
                            result,
                            (int)resultPos,
                            (int)Math.Min(subchunks[i].Item2, _stream.total_out - resultPos));

                        resultPos += subchunks[i].Item2;
                    }

                    return(result);
                }
                else
                {
                    return(new byte[0]);
                }
            }

            Debug.Fail(null);
            return(null);
        }
Пример #9
0
 /// <summary>
 /// Initializes a new instance of the class.
 /// </summary>
 public ZlibFilter()
     : base(null)
 {
     _state = ZlibState.NotStarted;
 }
Пример #10
0
 /// <summary>
 /// Initializes a new instance of the class.
 /// </summary>
 public ZlibFilter()
 {
     _state = ZlibState.NotStarted;
 }
Пример #11
0
        /// <summary>
        /// 处理写。
        /// </summary>
        /// <param name="state">状态。</param>
        private void PerpetualWriterMethod(object state)
        {
#if Zip_Trace
            TraceOutput(TraceBits.WriterThread, "_PerpetualWriterMethod START");
#endif
            try {
                do
                {
                    // wait for the next session
#if Zip_Trace
                    TraceOutput(TraceBits.Synch | TraceBits.WriterThread, "Synch    _sessionReset.WaitOne(begin) PWM");
#endif
                    _sessionReset.WaitOne();
#if Zip_Trace
                    TraceOutput(TraceBits.Synch | TraceBits.WriterThread, "Synch    _sessionReset.WaitOne(done)  PWM");
#endif
                    if (_isDisposed)
                    {
                        break;
                    }
#if Zip_Trace
                    TraceOutput(TraceBits.Synch | TraceBits.WriterThread, "Synch    _sessionReset.Reset()        PWM");
#endif
                    _sessionReset.Reset();

                    // repeatedly write buffers as they become ready
                    WorkItem           workitem = null;
                    Py.Algorithm.Crc32 c        = new Py.Algorithm.Crc32();
                    do
                    {
                        workitem = _pool[_nextToWrite % _pc];
                        lock (workitem) {
#if Zip_Trace
                            if (_noMoreInputForThisSegment)
                            {
                                TraceOutput(TraceBits.Write,
                                            "Write    drain    wi({0}) stat({1}) canuse({2})  cba({3})",
                                            workitem.Index,
                                            workitem.CurrentStatus,
                                            (workitem.CurrentStatus == WorkItem.Status.Compressed),
                                            workitem.CompressedBytesAvailable);
                            }
#endif

                            do
                            {
                                if (workitem.CurrentStatus == WorkItem.Status.Compressed)
                                {
#if Zip_Trace
                                    TraceOutput(TraceBits.WriteBegin,
                                                "Write    begin    wi({0}) stat({1})              cba({2})",
                                                workitem.Index,
                                                workitem.CurrentStatus,
                                                workitem.CompressedBytesAvailable);
#endif

                                    workitem.CurrentStatus = WorkItem.Status.Writing;
                                    _outStream.Write(workitem.Compressed, 0, workitem.CompressedBytesAvailable);
                                    c.Combine(workitem.Crc, workitem.InputBytesAvailable);
                                    _totalBytesProcessed += workitem.InputBytesAvailable;
                                    _nextToWrite++;
                                    workitem.InputBytesAvailable = 0;
                                    workitem.CurrentStatus       = WorkItem.Status.Done;
#if Zip_Trace
                                    TraceOutput(TraceBits.WriteDone,
                                                "Write    done     wi({0}) stat({1})              cba({2})",
                                                workitem.Index,
                                                workitem.CurrentStatus,
                                                workitem.CompressedBytesAvailable);
#endif
                                    Monitor.Pulse(workitem);
                                    break;
                                }
                                else
                                {
                                    int wcycles = 0;
                                    // I've locked a workitem I cannot use.
                                    // Therefore, wake someone else up, and then release the lock.
                                    while (workitem.CurrentStatus != WorkItem.Status.Compressed)
                                    {
#if Zip_Trace
                                        TraceOutput(TraceBits.WriteWait,
                                                    "Write    waiting  wi({0}) stat({1}) nw({2}) nf({3}) nomore({4})",
                                                    workitem.Index,
                                                    workitem.CurrentStatus,
                                                    _nextToWrite, _nextToFill,
                                                    _noMoreInputForThisSegment);
#endif
                                        if (_noMoreInputForThisSegment && _nextToWrite == _nextToFill)
                                        {
                                            break;
                                        }

                                        wcycles++;

                                        // wake up someone else
                                        Monitor.Pulse(workitem);
                                        // release and wait
                                        Monitor.Wait(workitem);
#if Zip_Trace
                                        if (workitem.CurrentStatus == WorkItem.Status.Compressed)
                                        {
                                            TraceOutput(TraceBits.WriteWait,
                                                        "Write    A-OK     wi({0}) stat({1}) iba({2}) cba({3}) cyc({4})",
                                                        workitem.Index,
                                                        workitem.CurrentStatus,
                                                        workitem.InputBytesAvailable,
                                                        workitem.CompressedBytesAvailable,
                                                        wcycles);
                                        }
#endif
                                    }

                                    if (_noMoreInputForThisSegment && _nextToWrite == _nextToFill)
                                    {
                                        break;
                                    }
                                }
                            }while (true);
                        }
#if Zip_Trace
                        if (_noMoreInputForThisSegment)
                        {
                            TraceOutput(TraceBits.Write,
                                        "Write    nomore  nw({0}) nf({1}) break({2})",
                                        _nextToWrite, _nextToFill, (_nextToWrite == _nextToFill));
                        }
#endif
                        if (_noMoreInputForThisSegment && _nextToWrite == _nextToFill)
                        {
                            break;
                        }
                    } while (true);


                    // Finish:
                    // After writing a series of buffers, closing each one with
                    // Flush.Sync, we now write the final one as Flush.Finish, and
                    // then stop.
                    byte[]    buffer     = new byte[128];
                    ZlibCodec compressor = new ZlibCodec();
                    ZlibState rc         = compressor.InitializeDeflate(_compressLevel, false);
                    compressor.InputBuffer       = null;
                    compressor.NextIn            = 0;
                    compressor.AvailableBytesIn  = 0;
                    compressor.OutputBuffer      = buffer;
                    compressor.NextOut           = 0;
                    compressor.AvailableBytesOut = buffer.Length;
                    rc = compressor.Deflate(FlushType.Finish);
                    if (rc != ZlibState.StreamEnd && rc != ZlibState.Success)
                    {
                        throw new ZlibException("压缩错误: " + compressor.Message);
                    }

                    if (buffer.Length - compressor.AvailableBytesOut > 0)
                    {
#if Zip_Trace
                        TraceOutput(TraceBits.WriteBegin,
                                    "Write    begin    flush bytes({0})",
                                    buffer.Length - compressor.AvailableBytesOut);
#endif

                        _outStream.Write(buffer, 0, buffer.Length - compressor.AvailableBytesOut);

#if Zip_Trace
                        TraceOutput(TraceBits.WriteBegin,
                                    "Write    done     flush");
#endif
                    }

                    compressor.EndDeflate();

                    _Crc32 = c.Crc32Result;

                    // signal that writing is complete:
#if Zip_Trace
                    TraceOutput(TraceBits.Synch, "Synch    _writingDone.Set()           PWM");
#endif
                    _writingDone.Set();
                }while (true);
            } catch (System.Exception exc1) {
                lock (_eLock) {
                    // expose the exception to the main thread
                    if (_pendingException != null)
                    {
                        _pendingException = exc1;
                    }
                }
            }
#if Zip_Trace
            TraceOutput(TraceBits.WriterThread, "_PerpetualWriterMethod FINIS");
#endif
        }