1275793eaSopenharmony_ci// 2275793eaSopenharmony_ci// � Copyright Henrik Ravn 2004 3275793eaSopenharmony_ci// 4275793eaSopenharmony_ci// Use, modification and distribution are subject to the Boost Software License, Version 1.0. 5275793eaSopenharmony_ci// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6275793eaSopenharmony_ci// 7275793eaSopenharmony_ci 8275793eaSopenharmony_ciusing System; 9275793eaSopenharmony_ciusing System.IO; 10275793eaSopenharmony_ciusing System.Runtime.InteropServices; 11275793eaSopenharmony_ci 12275793eaSopenharmony_cinamespace DotZLib 13275793eaSopenharmony_ci{ 14275793eaSopenharmony_ci /// <summary> 15275793eaSopenharmony_ci /// Implements a compressed <see cref="Stream"/>, in GZip (.gz) format. 16275793eaSopenharmony_ci /// </summary> 17275793eaSopenharmony_ci public class GZipStream : Stream, IDisposable 18275793eaSopenharmony_ci { 19275793eaSopenharmony_ci #region Dll Imports 20275793eaSopenharmony_ci [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl, CharSet=CharSet.Ansi)] 21275793eaSopenharmony_ci private static extern IntPtr gzopen(string name, string mode); 22275793eaSopenharmony_ci 23275793eaSopenharmony_ci [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] 24275793eaSopenharmony_ci private static extern int gzclose(IntPtr gzFile); 25275793eaSopenharmony_ci 26275793eaSopenharmony_ci [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] 27275793eaSopenharmony_ci private static extern int gzwrite(IntPtr gzFile, int data, int length); 28275793eaSopenharmony_ci 29275793eaSopenharmony_ci [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] 30275793eaSopenharmony_ci private static extern int gzread(IntPtr gzFile, int data, int length); 31275793eaSopenharmony_ci 32275793eaSopenharmony_ci [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] 33275793eaSopenharmony_ci private static extern int gzgetc(IntPtr gzFile); 34275793eaSopenharmony_ci 35275793eaSopenharmony_ci [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] 36275793eaSopenharmony_ci private static extern int gzputc(IntPtr gzFile, int c); 37275793eaSopenharmony_ci 38275793eaSopenharmony_ci #endregion 39275793eaSopenharmony_ci 40275793eaSopenharmony_ci #region Private data 41275793eaSopenharmony_ci private IntPtr _gzFile; 42275793eaSopenharmony_ci private bool _isDisposed = false; 43275793eaSopenharmony_ci private bool _isWriting; 44275793eaSopenharmony_ci #endregion 45275793eaSopenharmony_ci 46275793eaSopenharmony_ci #region Constructors 47275793eaSopenharmony_ci /// <summary> 48275793eaSopenharmony_ci /// Creates a new file as a writeable GZipStream 49275793eaSopenharmony_ci /// </summary> 50275793eaSopenharmony_ci /// <param name="fileName">The name of the compressed file to create</param> 51275793eaSopenharmony_ci /// <param name="level">The compression level to use when adding data</param> 52275793eaSopenharmony_ci /// <exception cref="ZLibException">If an error occurred in the internal zlib function</exception> 53275793eaSopenharmony_ci public GZipStream(string fileName, CompressLevel level) 54275793eaSopenharmony_ci { 55275793eaSopenharmony_ci _isWriting = true; 56275793eaSopenharmony_ci _gzFile = gzopen(fileName, String.Format("wb{0}", (int)level)); 57275793eaSopenharmony_ci if (_gzFile == IntPtr.Zero) 58275793eaSopenharmony_ci throw new ZLibException(-1, "Could not open " + fileName); 59275793eaSopenharmony_ci } 60275793eaSopenharmony_ci 61275793eaSopenharmony_ci /// <summary> 62275793eaSopenharmony_ci /// Opens an existing file as a readable GZipStream 63275793eaSopenharmony_ci /// </summary> 64275793eaSopenharmony_ci /// <param name="fileName">The name of the file to open</param> 65275793eaSopenharmony_ci /// <exception cref="ZLibException">If an error occurred in the internal zlib function</exception> 66275793eaSopenharmony_ci public GZipStream(string fileName) 67275793eaSopenharmony_ci { 68275793eaSopenharmony_ci _isWriting = false; 69275793eaSopenharmony_ci _gzFile = gzopen(fileName, "rb"); 70275793eaSopenharmony_ci if (_gzFile == IntPtr.Zero) 71275793eaSopenharmony_ci throw new ZLibException(-1, "Could not open " + fileName); 72275793eaSopenharmony_ci 73275793eaSopenharmony_ci } 74275793eaSopenharmony_ci #endregion 75275793eaSopenharmony_ci 76275793eaSopenharmony_ci #region Access properties 77275793eaSopenharmony_ci /// <summary> 78275793eaSopenharmony_ci /// Returns true of this stream can be read from, false otherwise 79275793eaSopenharmony_ci /// </summary> 80275793eaSopenharmony_ci public override bool CanRead 81275793eaSopenharmony_ci { 82275793eaSopenharmony_ci get 83275793eaSopenharmony_ci { 84275793eaSopenharmony_ci return !_isWriting; 85275793eaSopenharmony_ci } 86275793eaSopenharmony_ci } 87275793eaSopenharmony_ci 88275793eaSopenharmony_ci 89275793eaSopenharmony_ci /// <summary> 90275793eaSopenharmony_ci /// Returns false. 91275793eaSopenharmony_ci /// </summary> 92275793eaSopenharmony_ci public override bool CanSeek 93275793eaSopenharmony_ci { 94275793eaSopenharmony_ci get 95275793eaSopenharmony_ci { 96275793eaSopenharmony_ci return false; 97275793eaSopenharmony_ci } 98275793eaSopenharmony_ci } 99275793eaSopenharmony_ci 100275793eaSopenharmony_ci /// <summary> 101275793eaSopenharmony_ci /// Returns true if this tsream is writeable, false otherwise 102275793eaSopenharmony_ci /// </summary> 103275793eaSopenharmony_ci public override bool CanWrite 104275793eaSopenharmony_ci { 105275793eaSopenharmony_ci get 106275793eaSopenharmony_ci { 107275793eaSopenharmony_ci return _isWriting; 108275793eaSopenharmony_ci } 109275793eaSopenharmony_ci } 110275793eaSopenharmony_ci #endregion 111275793eaSopenharmony_ci 112275793eaSopenharmony_ci #region Destructor & IDispose stuff 113275793eaSopenharmony_ci 114275793eaSopenharmony_ci /// <summary> 115275793eaSopenharmony_ci /// Destroys this instance 116275793eaSopenharmony_ci /// </summary> 117275793eaSopenharmony_ci ~GZipStream() 118275793eaSopenharmony_ci { 119275793eaSopenharmony_ci cleanUp(false); 120275793eaSopenharmony_ci } 121275793eaSopenharmony_ci 122275793eaSopenharmony_ci /// <summary> 123275793eaSopenharmony_ci /// Closes the external file handle 124275793eaSopenharmony_ci /// </summary> 125275793eaSopenharmony_ci public void Dispose() 126275793eaSopenharmony_ci { 127275793eaSopenharmony_ci cleanUp(true); 128275793eaSopenharmony_ci } 129275793eaSopenharmony_ci 130275793eaSopenharmony_ci // Does the actual closing of the file handle. 131275793eaSopenharmony_ci private void cleanUp(bool isDisposing) 132275793eaSopenharmony_ci { 133275793eaSopenharmony_ci if (!_isDisposed) 134275793eaSopenharmony_ci { 135275793eaSopenharmony_ci gzclose(_gzFile); 136275793eaSopenharmony_ci _isDisposed = true; 137275793eaSopenharmony_ci } 138275793eaSopenharmony_ci } 139275793eaSopenharmony_ci #endregion 140275793eaSopenharmony_ci 141275793eaSopenharmony_ci #region Basic reading and writing 142275793eaSopenharmony_ci /// <summary> 143275793eaSopenharmony_ci /// Attempts to read a number of bytes from the stream. 144275793eaSopenharmony_ci /// </summary> 145275793eaSopenharmony_ci /// <param name="buffer">The destination data buffer</param> 146275793eaSopenharmony_ci /// <param name="offset">The index of the first destination byte in <c>buffer</c></param> 147275793eaSopenharmony_ci /// <param name="count">The number of bytes requested</param> 148275793eaSopenharmony_ci /// <returns>The number of bytes read</returns> 149275793eaSopenharmony_ci /// <exception cref="ArgumentNullException">If <c>buffer</c> is null</exception> 150275793eaSopenharmony_ci /// <exception cref="ArgumentOutOfRangeException">If <c>count</c> or <c>offset</c> are negative</exception> 151275793eaSopenharmony_ci /// <exception cref="ArgumentException">If <c>offset</c> + <c>count</c> is > buffer.Length</exception> 152275793eaSopenharmony_ci /// <exception cref="NotSupportedException">If this stream is not readable.</exception> 153275793eaSopenharmony_ci /// <exception cref="ObjectDisposedException">If this stream has been disposed.</exception> 154275793eaSopenharmony_ci public override int Read(byte[] buffer, int offset, int count) 155275793eaSopenharmony_ci { 156275793eaSopenharmony_ci if (!CanRead) throw new NotSupportedException(); 157275793eaSopenharmony_ci if (buffer == null) throw new ArgumentNullException(); 158275793eaSopenharmony_ci if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException(); 159275793eaSopenharmony_ci if ((offset+count) > buffer.Length) throw new ArgumentException(); 160275793eaSopenharmony_ci if (_isDisposed) throw new ObjectDisposedException("GZipStream"); 161275793eaSopenharmony_ci 162275793eaSopenharmony_ci GCHandle h = GCHandle.Alloc(buffer, GCHandleType.Pinned); 163275793eaSopenharmony_ci int result; 164275793eaSopenharmony_ci try 165275793eaSopenharmony_ci { 166275793eaSopenharmony_ci result = gzread(_gzFile, h.AddrOfPinnedObject().ToInt32() + offset, count); 167275793eaSopenharmony_ci if (result < 0) 168275793eaSopenharmony_ci throw new IOException(); 169275793eaSopenharmony_ci } 170275793eaSopenharmony_ci finally 171275793eaSopenharmony_ci { 172275793eaSopenharmony_ci h.Free(); 173275793eaSopenharmony_ci } 174275793eaSopenharmony_ci return result; 175275793eaSopenharmony_ci } 176275793eaSopenharmony_ci 177275793eaSopenharmony_ci /// <summary> 178275793eaSopenharmony_ci /// Attempts to read a single byte from the stream. 179275793eaSopenharmony_ci /// </summary> 180275793eaSopenharmony_ci /// <returns>The byte that was read, or -1 in case of error or End-Of-File</returns> 181275793eaSopenharmony_ci public override int ReadByte() 182275793eaSopenharmony_ci { 183275793eaSopenharmony_ci if (!CanRead) throw new NotSupportedException(); 184275793eaSopenharmony_ci if (_isDisposed) throw new ObjectDisposedException("GZipStream"); 185275793eaSopenharmony_ci return gzgetc(_gzFile); 186275793eaSopenharmony_ci } 187275793eaSopenharmony_ci 188275793eaSopenharmony_ci /// <summary> 189275793eaSopenharmony_ci /// Writes a number of bytes to the stream 190275793eaSopenharmony_ci /// </summary> 191275793eaSopenharmony_ci /// <param name="buffer"></param> 192275793eaSopenharmony_ci /// <param name="offset"></param> 193275793eaSopenharmony_ci /// <param name="count"></param> 194275793eaSopenharmony_ci /// <exception cref="ArgumentNullException">If <c>buffer</c> is null</exception> 195275793eaSopenharmony_ci /// <exception cref="ArgumentOutOfRangeException">If <c>count</c> or <c>offset</c> are negative</exception> 196275793eaSopenharmony_ci /// <exception cref="ArgumentException">If <c>offset</c> + <c>count</c> is > buffer.Length</exception> 197275793eaSopenharmony_ci /// <exception cref="NotSupportedException">If this stream is not writeable.</exception> 198275793eaSopenharmony_ci /// <exception cref="ObjectDisposedException">If this stream has been disposed.</exception> 199275793eaSopenharmony_ci public override void Write(byte[] buffer, int offset, int count) 200275793eaSopenharmony_ci { 201275793eaSopenharmony_ci if (!CanWrite) throw new NotSupportedException(); 202275793eaSopenharmony_ci if (buffer == null) throw new ArgumentNullException(); 203275793eaSopenharmony_ci if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException(); 204275793eaSopenharmony_ci if ((offset+count) > buffer.Length) throw new ArgumentException(); 205275793eaSopenharmony_ci if (_isDisposed) throw new ObjectDisposedException("GZipStream"); 206275793eaSopenharmony_ci 207275793eaSopenharmony_ci GCHandle h = GCHandle.Alloc(buffer, GCHandleType.Pinned); 208275793eaSopenharmony_ci try 209275793eaSopenharmony_ci { 210275793eaSopenharmony_ci int result = gzwrite(_gzFile, h.AddrOfPinnedObject().ToInt32() + offset, count); 211275793eaSopenharmony_ci if (result < 0) 212275793eaSopenharmony_ci throw new IOException(); 213275793eaSopenharmony_ci } 214275793eaSopenharmony_ci finally 215275793eaSopenharmony_ci { 216275793eaSopenharmony_ci h.Free(); 217275793eaSopenharmony_ci } 218275793eaSopenharmony_ci } 219275793eaSopenharmony_ci 220275793eaSopenharmony_ci /// <summary> 221275793eaSopenharmony_ci /// Writes a single byte to the stream 222275793eaSopenharmony_ci /// </summary> 223275793eaSopenharmony_ci /// <param name="value">The byte to add to the stream.</param> 224275793eaSopenharmony_ci /// <exception cref="NotSupportedException">If this stream is not writeable.</exception> 225275793eaSopenharmony_ci /// <exception cref="ObjectDisposedException">If this stream has been disposed.</exception> 226275793eaSopenharmony_ci public override void WriteByte(byte value) 227275793eaSopenharmony_ci { 228275793eaSopenharmony_ci if (!CanWrite) throw new NotSupportedException(); 229275793eaSopenharmony_ci if (_isDisposed) throw new ObjectDisposedException("GZipStream"); 230275793eaSopenharmony_ci 231275793eaSopenharmony_ci int result = gzputc(_gzFile, (int)value); 232275793eaSopenharmony_ci if (result < 0) 233275793eaSopenharmony_ci throw new IOException(); 234275793eaSopenharmony_ci } 235275793eaSopenharmony_ci #endregion 236275793eaSopenharmony_ci 237275793eaSopenharmony_ci #region Position & length stuff 238275793eaSopenharmony_ci /// <summary> 239275793eaSopenharmony_ci /// Not supported. 240275793eaSopenharmony_ci /// </summary> 241275793eaSopenharmony_ci /// <param name="value"></param> 242275793eaSopenharmony_ci /// <exception cref="NotSupportedException">Always thrown</exception> 243275793eaSopenharmony_ci public override void SetLength(long value) 244275793eaSopenharmony_ci { 245275793eaSopenharmony_ci throw new NotSupportedException(); 246275793eaSopenharmony_ci } 247275793eaSopenharmony_ci 248275793eaSopenharmony_ci /// <summary> 249275793eaSopenharmony_ci /// Not supported. 250275793eaSopenharmony_ci /// </summary> 251275793eaSopenharmony_ci /// <param name="offset"></param> 252275793eaSopenharmony_ci /// <param name="origin"></param> 253275793eaSopenharmony_ci /// <returns></returns> 254275793eaSopenharmony_ci /// <exception cref="NotSupportedException">Always thrown</exception> 255275793eaSopenharmony_ci public override long Seek(long offset, SeekOrigin origin) 256275793eaSopenharmony_ci { 257275793eaSopenharmony_ci throw new NotSupportedException(); 258275793eaSopenharmony_ci } 259275793eaSopenharmony_ci 260275793eaSopenharmony_ci /// <summary> 261275793eaSopenharmony_ci /// Flushes the <c>GZipStream</c>. 262275793eaSopenharmony_ci /// </summary> 263275793eaSopenharmony_ci /// <remarks>In this implementation, this method does nothing. This is because excessive 264275793eaSopenharmony_ci /// flushing may degrade the achievable compression rates.</remarks> 265275793eaSopenharmony_ci public override void Flush() 266275793eaSopenharmony_ci { 267275793eaSopenharmony_ci // left empty on purpose 268275793eaSopenharmony_ci } 269275793eaSopenharmony_ci 270275793eaSopenharmony_ci /// <summary> 271275793eaSopenharmony_ci /// Gets/sets the current position in the <c>GZipStream</c>. Not supported. 272275793eaSopenharmony_ci /// </summary> 273275793eaSopenharmony_ci /// <remarks>In this implementation this property is not supported</remarks> 274275793eaSopenharmony_ci /// <exception cref="NotSupportedException">Always thrown</exception> 275275793eaSopenharmony_ci public override long Position 276275793eaSopenharmony_ci { 277275793eaSopenharmony_ci get 278275793eaSopenharmony_ci { 279275793eaSopenharmony_ci throw new NotSupportedException(); 280275793eaSopenharmony_ci } 281275793eaSopenharmony_ci set 282275793eaSopenharmony_ci { 283275793eaSopenharmony_ci throw new NotSupportedException(); 284275793eaSopenharmony_ci } 285275793eaSopenharmony_ci } 286275793eaSopenharmony_ci 287275793eaSopenharmony_ci /// <summary> 288275793eaSopenharmony_ci /// Gets the size of the stream. Not supported. 289275793eaSopenharmony_ci /// </summary> 290275793eaSopenharmony_ci /// <remarks>In this implementation this property is not supported</remarks> 291275793eaSopenharmony_ci /// <exception cref="NotSupportedException">Always thrown</exception> 292275793eaSopenharmony_ci public override long Length 293275793eaSopenharmony_ci { 294275793eaSopenharmony_ci get 295275793eaSopenharmony_ci { 296275793eaSopenharmony_ci throw new NotSupportedException(); 297275793eaSopenharmony_ci } 298275793eaSopenharmony_ci } 299275793eaSopenharmony_ci #endregion 300275793eaSopenharmony_ci } 301275793eaSopenharmony_ci} 302