all repos — mgba @ 3b353ac62190a00765812938e86e04b753196736

mGBA Game Boy Advance Emulator

src/third-party/zlib/contrib/dotzlib/DotZLib/GZipStream.cs (view raw)

  1//
  2// � Copyright Henrik Ravn 2004
  3//
  4// Use, modification and distribution are subject to the Boost Software License, Version 1.0.
  5// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6//
  7
  8using System;
  9using System.IO;
 10using System.Runtime.InteropServices;
 11
 12namespace DotZLib
 13{
 14	/// <summary>
 15	/// Implements a compressed <see cref="Stream"/>, in GZip (.gz) format.
 16	/// </summary>
 17	public class GZipStream : Stream, IDisposable
 18	{
 19        #region Dll Imports
 20        [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl, CharSet=CharSet.Ansi)]
 21        private static extern IntPtr gzopen(string name, string mode);
 22
 23        [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
 24        private static extern int gzclose(IntPtr gzFile);
 25
 26        [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
 27        private static extern int gzwrite(IntPtr gzFile, int data, int length);
 28
 29        [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
 30        private static extern int gzread(IntPtr gzFile, int data, int length);
 31
 32        [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
 33        private static extern int gzgetc(IntPtr gzFile);
 34
 35        [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
 36        private static extern int gzputc(IntPtr gzFile, int c);
 37
 38        #endregion
 39
 40        #region Private data
 41        private IntPtr _gzFile;
 42        private bool _isDisposed = false;
 43        private bool _isWriting;
 44        #endregion
 45
 46        #region Constructors
 47        /// <summary>
 48        /// Creates a new file as a writeable GZipStream
 49        /// </summary>
 50        /// <param name="fileName">The name of the compressed file to create</param>
 51        /// <param name="level">The compression level to use when adding data</param>
 52        /// <exception cref="ZLibException">If an error occurred in the internal zlib function</exception>
 53		public GZipStream(string fileName, CompressLevel level)
 54		{
 55            _isWriting = true;
 56            _gzFile = gzopen(fileName, String.Format("wb{0}", (int)level));
 57            if (_gzFile == IntPtr.Zero)
 58                throw new ZLibException(-1, "Could not open " + fileName);
 59		}
 60
 61        /// <summary>
 62        /// Opens an existing file as a readable GZipStream
 63        /// </summary>
 64        /// <param name="fileName">The name of the file to open</param>
 65        /// <exception cref="ZLibException">If an error occurred in the internal zlib function</exception>
 66        public GZipStream(string fileName)
 67        {
 68            _isWriting = false;
 69            _gzFile = gzopen(fileName, "rb");
 70            if (_gzFile == IntPtr.Zero)
 71                throw new ZLibException(-1, "Could not open " + fileName);
 72
 73        }
 74        #endregion
 75
 76        #region Access properties
 77        /// <summary>
 78        /// Returns true of this stream can be read from, false otherwise
 79        /// </summary>
 80        public override bool CanRead
 81        {
 82            get
 83            {
 84                return !_isWriting;
 85            }
 86        }
 87
 88
 89        /// <summary>
 90        /// Returns false.
 91        /// </summary>
 92        public override bool CanSeek
 93        {
 94            get
 95            {
 96                return false;
 97            }
 98        }
 99
100        /// <summary>
101        /// Returns true if this tsream is writeable, false otherwise
102        /// </summary>
103        public override bool CanWrite
104        {
105            get
106            {
107                return _isWriting;
108            }
109        }
110        #endregion
111
112        #region Destructor & IDispose stuff
113
114        /// <summary>
115        /// Destroys this instance
116        /// </summary>
117        ~GZipStream()
118        {
119            cleanUp(false);
120        }
121
122        /// <summary>
123        /// Closes the external file handle
124        /// </summary>
125        public void Dispose()
126        {
127            cleanUp(true);
128        }
129
130        // Does the actual closing of the file handle.
131        private void cleanUp(bool isDisposing)
132        {
133            if (!_isDisposed)
134            {
135                gzclose(_gzFile);
136                _isDisposed = true;
137            }
138        }
139        #endregion
140
141        #region Basic reading and writing
142        /// <summary>
143        /// Attempts to read a number of bytes from the stream.
144        /// </summary>
145        /// <param name="buffer">The destination data buffer</param>
146        /// <param name="offset">The index of the first destination byte in <c>buffer</c></param>
147        /// <param name="count">The number of bytes requested</param>
148        /// <returns>The number of bytes read</returns>
149        /// <exception cref="ArgumentNullException">If <c>buffer</c> is null</exception>
150        /// <exception cref="ArgumentOutOfRangeException">If <c>count</c> or <c>offset</c> are negative</exception>
151        /// <exception cref="ArgumentException">If <c>offset</c>  + <c>count</c> is &gt; buffer.Length</exception>
152        /// <exception cref="NotSupportedException">If this stream is not readable.</exception>
153        /// <exception cref="ObjectDisposedException">If this stream has been disposed.</exception>
154        public override int Read(byte[] buffer, int offset, int count)
155        {
156            if (!CanRead) throw new NotSupportedException();
157            if (buffer == null) throw new ArgumentNullException();
158            if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException();
159            if ((offset+count) > buffer.Length) throw new ArgumentException();
160            if (_isDisposed) throw new ObjectDisposedException("GZipStream");
161
162            GCHandle h = GCHandle.Alloc(buffer, GCHandleType.Pinned);
163            int result;
164            try
165            {
166                result = gzread(_gzFile, h.AddrOfPinnedObject().ToInt32() + offset, count);
167                if (result < 0)
168                    throw new IOException();
169            }
170            finally
171            {
172                h.Free();
173            }
174            return result;
175        }
176
177        /// <summary>
178        /// Attempts to read a single byte from the stream.
179        /// </summary>
180        /// <returns>The byte that was read, or -1 in case of error or End-Of-File</returns>
181        public override int ReadByte()
182        {
183            if (!CanRead) throw new NotSupportedException();
184            if (_isDisposed) throw new ObjectDisposedException("GZipStream");
185            return gzgetc(_gzFile);
186        }
187
188        /// <summary>
189        /// Writes a number of bytes to the stream
190        /// </summary>
191        /// <param name="buffer"></param>
192        /// <param name="offset"></param>
193        /// <param name="count"></param>
194        /// <exception cref="ArgumentNullException">If <c>buffer</c> is null</exception>
195        /// <exception cref="ArgumentOutOfRangeException">If <c>count</c> or <c>offset</c> are negative</exception>
196        /// <exception cref="ArgumentException">If <c>offset</c>  + <c>count</c> is &gt; buffer.Length</exception>
197        /// <exception cref="NotSupportedException">If this stream is not writeable.</exception>
198        /// <exception cref="ObjectDisposedException">If this stream has been disposed.</exception>
199        public override void Write(byte[] buffer, int offset, int count)
200        {
201            if (!CanWrite) throw new NotSupportedException();
202            if (buffer == null) throw new ArgumentNullException();
203            if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException();
204            if ((offset+count) > buffer.Length) throw new ArgumentException();
205            if (_isDisposed) throw new ObjectDisposedException("GZipStream");
206
207            GCHandle h = GCHandle.Alloc(buffer, GCHandleType.Pinned);
208            try
209            {
210                int result = gzwrite(_gzFile, h.AddrOfPinnedObject().ToInt32() + offset, count);
211                if (result < 0)
212                    throw new IOException();
213            }
214            finally
215            {
216                h.Free();
217            }
218        }
219
220        /// <summary>
221        /// Writes a single byte to the stream
222        /// </summary>
223        /// <param name="value">The byte to add to the stream.</param>
224        /// <exception cref="NotSupportedException">If this stream is not writeable.</exception>
225        /// <exception cref="ObjectDisposedException">If this stream has been disposed.</exception>
226        public override void WriteByte(byte value)
227        {
228            if (!CanWrite) throw new NotSupportedException();
229            if (_isDisposed) throw new ObjectDisposedException("GZipStream");
230
231            int result = gzputc(_gzFile, (int)value);
232            if (result < 0)
233                throw new IOException();
234        }
235        #endregion
236
237        #region Position & length stuff
238        /// <summary>
239        /// Not supported.
240        /// </summary>
241        /// <param name="value"></param>
242        /// <exception cref="NotSupportedException">Always thrown</exception>
243        public override void SetLength(long value)
244        {
245            throw new NotSupportedException();
246        }
247
248        /// <summary>
249        ///  Not suppported.
250        /// </summary>
251        /// <param name="offset"></param>
252        /// <param name="origin"></param>
253        /// <returns></returns>
254        /// <exception cref="NotSupportedException">Always thrown</exception>
255        public override long Seek(long offset, SeekOrigin origin)
256        {
257            throw new NotSupportedException();
258        }
259
260        /// <summary>
261        /// Flushes the <c>GZipStream</c>.
262        /// </summary>
263        /// <remarks>In this implementation, this method does nothing. This is because excessive
264        /// flushing may degrade the achievable compression rates.</remarks>
265        public override void Flush()
266        {
267            // left empty on purpose
268        }
269
270        /// <summary>
271        /// Gets/sets the current position in the <c>GZipStream</c>. Not suppported.
272        /// </summary>
273        /// <remarks>In this implementation this property is not supported</remarks>
274        /// <exception cref="NotSupportedException">Always thrown</exception>
275        public override long Position
276        {
277            get
278            {
279                throw new NotSupportedException();
280            }
281            set
282            {
283                throw new NotSupportedException();
284            }
285        }
286
287        /// <summary>
288        /// Gets the size of the stream. Not suppported.
289        /// </summary>
290        /// <remarks>In this implementation this property is not supported</remarks>
291        /// <exception cref="NotSupportedException">Always thrown</exception>
292        public override long Length
293        {
294            get
295            {
296                throw new NotSupportedException();
297            }
298        }
299        #endregion
300    }
301}