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 &gt; 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 &gt; 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