/// <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(); } }
/// <summary> /// 停止处理。 /// </summary> /// <returns>如果正常返回 ZlibState.Success 。</returns> public ZlibState EndInflate() { Thrower.ThrowZlibExceptionIf(IState == null, "没有初始化 Inflate 状态。"); ZlibState ret = IState.End(); IState = null; return(ret); }
/// <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); }
/// <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("非法的模式。"); } }
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); } }
/// <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; }
/// <summary> /// Initializes a new instance of the class. /// </summary> public ZlibFilter() : base(null) { _state = ZlibState.NotStarted; }
/// <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); }
/// <summary> /// Initializes a new instance of the class. /// </summary> public ZlibFilter() { _state = ZlibState.NotStarted; }
/// <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 }