/// <summary> /// Writes a number of bytes to the stream /// </summary> /// <param name="buffer"></param> /// <param name="length"></param> /// <param name="offset"></param> /// <param name="count"></param> /// <exception cref="ArgumentNullException">If <c>buffer</c> is null</exception> /// <exception cref="ArgumentOutOfRangeException">If <c>count</c> or <c>offset</c> are negative</exception> /// <exception cref="ArgumentException">If <c>offset</c> + <c>count</c> is > buffer.Length</exception> /// <exception cref="NotSupportedException">If this stream is not writeable.</exception> /// <exception cref="ObjectDisposedException">If this stream has been disposed.</exception> public unsafe void Write(byte *buffer, int length, int offset, int count) { if (!CanWrite) { throw new NotSupportedException(); } if (buffer == null) { throw new ArgumentNullException(); } if (offset < 0 || count < 0) { throw new ArgumentOutOfRangeException(); } if ((offset + count) > length) { throw new ArgumentException(); } if (_isDisposed) { throw new ObjectDisposedException("GZipStream"); } var result = ZLibNative.gzwrite(_gzFile, buffer + offset, count); if (result < 0) { throw new IOException(); } }
/// <summary>Closes the current stream and releases any resources (such as sockets and file handles) associated with the current stream.</summary> public unsafe override void Close() { if (_isClosed) { return; } _isClosed = true; if (_mode == CompressionMode.Compress) { if (_writeAfterReset) { Write(null, 0, ZLibFlush.Finish); } ZLibNative.deflateEnd(ref _zstream); } else { ZLibNative.inflateEnd(ref _zstream); } if (CloseUnderlyingStream) { _stream.Close(); } _tmpBufferHandle.Free(); base.Close(); }
// Does the actual closing of the file handle. void CleanUp(bool isDisposing) { if (_isDisposed) { return; } ZLibNative.gzclose(_gzFile); _isDisposed = true; }
/// <summary> /// Attempts to read a single byte from the stream. /// </summary> /// <returns>The byte that was read, or -1 in case of error or End-Of-File</returns> public override int ReadByte() { if (!CanRead) { throw new NotSupportedException(); } if (_isDisposed) { throw new ObjectDisposedException("GZipStream"); } return(ZLibNative.gzgetc(_gzFile)); }
/// <exception cref="NotSupportedException">The stream must be in decompress mode to read from.</exception> /// <exception cref="ArgumentNullException"><paramref name="p"/> is <see langword="null" />.</exception> /// <exception cref="ArgumentOutOfRangeException">length cannot be negative.</exception> /// <exception cref="ObjectDisposedException">The method cannot be called after the object has been disposed.</exception> public unsafe int Read(byte *p, int length) { if (!CanRead) { throw new NotSupportedException($"{nameof(GZipStream)} must be in decompress mode to read from"); } if (p == null) { throw new ArgumentNullException(nameof(p)); } if (length < 0) { throw new ArgumentOutOfRangeException(nameof(length), "length cannot be negative"); } if (_isDisposed) { throw new ObjectDisposedException(nameof(GZipStream)); } Contract.EndContractBlock(); var exitLoop = false; _zstream.next_out = p; _zstream.avail_out = (uint)length; while (_zstream.avail_out > 0 && exitLoop == false) { if (_zstream.avail_in == 0) { var readLength = _stream.Read(_tmpBuffer, 0, _tmpBuffer.Length); _zstream.avail_in = (uint)readLength; _zstream.next_in = (byte *)_tmpBufferPtr; } var result = ZLibNative.inflate(ref _zstream, ZLibFlush.NoFlush); switch (result) { case ZLibReturnCode.StreamEnd: exitLoop = true; break; case ZLibReturnCode.Ok: break; case ZLibReturnCode.MemError: throw new OutOfMemoryException($"ZLib return code: {result}"); default: throw new Exception($"ZLib return code: {result}"); } } return(length - (int)_zstream.avail_out); }
unsafe void Write(byte *buffer, int count, ZLibFlush flush) { if (_mode == CompressionMode.Decompress) { throw new NotSupportedException("Can't write on a decompress stream!"); } // This indicates that we need to go through a "Finish" write when closing/reseting _writeAfterReset = true; _zstream.avail_in = (uint)count; _zstream.next_in = buffer; uint availOut; do { var result = ZLibNative.deflate(ref _zstream, flush); availOut = _zstream.avail_out; if (availOut < BufferSize) { var outSize = BufferSize - availOut; _stream.Write(_tmpBuffer, 0, (int)outSize); _zstream.next_out = (byte *)_tmpBufferPtr; _zstream.avail_out = BufferSize; } // Translate erros into specific exceptions switch (result) { case ZLibReturnCode.Ok: continue; case ZLibReturnCode.StreamEnd: return; case ZLibReturnCode.MemError: throw new OutOfMemoryException("zlib return code: " + result); default: throw new Exception("zlib return code: " + result); } // We go one for two reasons: // 1. There's still more input available // 2. We're in some FLUSH/FINISH scenario // and the output buffer has no sufficient space left } while ((_zstream.avail_in > 0) || (flush != ZLibFlush.NoFlush && availOut == 0)); }
/// <summary>Initializes a new instance of the GZipStream class using the specified stream and BZip2CompressionMode value.</summary> /// <param name="stream">The stream to compress or decompress.</param> /// <param name="mode">One of the BZip2CompressionMode values that indicates the action to take.</param> /// <param name="options">The Gzip Options</param>ll public unsafe GZipStream(Stream stream, CompressionMode mode, GZipOptions options) { if (stream == null) { throw new ArgumentNullException("stream"); } _stream = stream; _mode = mode; _zstream.zalloc = null; _zstream.zfree = null; _zstream.opaque = null; _tmpBuffer = new byte[BufferSize]; _tmpBufferHandle = GCHandle.Alloc(_tmpBuffer, GCHandleType.Pinned); _tmpBufferPtr = _tmpBufferHandle.AddrOfPinnedObject().ToPointer(); ZLibReturnCode ret; switch (mode) { case CompressionMode.Compress: ret = ZLibNative.deflateInit2_(ref _zstream, options.Level, options.Method, options.WindowBits, options.MemoryLevel, (int)options.Strategy, ZLibVersion, Marshal.SizeOf(typeof(ZStream))); if (ret != ZLibReturnCode.Ok) { throw new ArgumentException("Unable to init ZLib. Return code: " + ret); } _zstream.next_out = (byte *)_tmpBufferPtr; _zstream.avail_out = (uint)_tmpBuffer.Length; break; case CompressionMode.Decompress: ret = ZLibNative.inflateInit2_(ref _zstream, options.WindowBits, ZLibVersion, Marshal.SizeOf(typeof(ZStream))); if (ret != ZLibReturnCode.Ok) { throw new ArgumentException("Unable to init ZLib. Return code: " + ret); } break; } }
/// <summary>Closes the current stream and releases any resources (such as sockets and file handles) associated with the current stream.</summary> public unsafe void Reset() { if (_isClosed) { return; } if (_mode == CompressionMode.Compress) { if (_writeAfterReset) { Write(null, 0, ZLibFlush.Finish); } _writeAfterReset = false; ZLibNative.deflateReset(ref _zstream); } else { ZLibNative.inflateReset(ref _zstream); } }
/// <summary> /// Opens an existing file as a readable GZipFileStream /// </summary> /// <param name="fileName">The name of the file to open</param> /// <param name="access">The file access pattern</param> /// <param name="level">The compression level to use</param> /// <exception cref="ZLibException">If an error occurred in the internal zlib function</exception> public GZipFileStream(string fileName, FileAccess access, CompressLevel level) { switch (access) { case FileAccess.Read: _isWriting = false; _gzFile = ZLibNative.gzopen(fileName, "rb"); break; case FileAccess.Write: _isWriting = true; _gzFile = ZLibNative.gzopen(fileName, String.Format("wb{0}", (int)level)); break; case FileAccess.ReadWrite: throw new ArgumentException(String.Format("{0} cannot be used with {1}", access, GetType().FullName), "access"); } if (_gzFile == IntPtr.Zero) { throw new ZLibException(-1, "Could not open " + fileName); } }
/// <summary> /// Constructs an instance of the <c>ZLibInfo</c> class. /// </summary> public ZLibInfo() { _flags = ZLibNative.zlibCompileFlags(); }