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