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