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