(DISTFILES): Comment out a few missing files.
[mono-project.git] / mcs / class / ICSharpCode.SharpZipLib / ICSharpCode.SharpZipLib / GZip / GZipInputStream.cs
blob5a35548e2fbcc172b6c74add1ad947cd012065be
1 // GzipInputStream.cs
2 // Copyright (C) 2001 Mike Krueger
3 //
4 // This file was translated from java, it was part of the GNU Classpath
5 // Copyright (C) 2001 Free Software Foundation, Inc.
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License
9 // as published by the Free Software Foundation; either version 2
10 // of the License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 // Linking this library statically or dynamically with other modules is
22 // making a combined work based on this library. Thus, the terms and
23 // conditions of the GNU General Public License cover the whole
24 // combination.
25 //
26 // As a special exception, the copyright holders of this library give you
27 // permission to link this library with independent modules to produce an
28 // executable, regardless of the license terms of these independent
29 // modules, and to copy and distribute the resulting executable under
30 // terms of your choice, provided that you also meet, for each linked
31 // independent module, the terms and conditions of the license of that
32 // module. An independent module is a module which is not derived from
33 // or based on this library. If you modify this library, you may extend
34 // this exception to your version of the library, but you are not
35 // obligated to do so. If you do not wish to do so, delete this
36 // exception statement from your version.
38 using System;
39 using System.IO;
41 using ICSharpCode.SharpZipLib.Checksums;
42 using ICSharpCode.SharpZipLib.Zip.Compression;
43 using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
45 namespace ICSharpCode.SharpZipLib.GZip
48 /// <summary>
49 /// This filter stream is used to decompress a "GZIP" format stream.
50 /// The "GZIP" format is described baseInputStream RFC 1952.
51 ///
52 /// author of the original java version : John Leuner
53 /// </summary>
54 /// <example> This sample shows how to unzip a gzipped file
55 /// <code>
56 /// using System;
57 /// using System.IO;
58 ///
59 /// using NZlib.GZip;
60 ///
61 /// class MainClass
62 /// {
63 /// public static void Main(string[] args)
64 /// {
65 /// Stream s = new GZipInputStream(File.OpenRead(args[0]));
66 /// FileStream fs = File.Create(Path.GetFileNameWithoutExtension(args[0]));
67 /// int size = 2048;
68 /// byte[] writeData = new byte[2048];
69 /// while (true) {
70 /// size = s.Read(writeData, 0, size);
71 /// if (size > 0) {
72 /// fs.Write(writeData, 0, size);
73 /// } else {
74 /// break;
75 /// }
76 /// }
77 /// s.Close();
78 /// }
79 /// }
80 /// </code>
81 /// </example>
82 public class GZipInputStream : InflaterInputStream
84 /// <summary>
85 /// CRC-32 value for uncompressed data
86 /// </summary>
87 protected Crc32 crc = new Crc32();
89 /// <summary>
90 /// Indicates end of stream
91 /// </summary>
92 protected bool eos;
94 // Have we read the GZIP header yet?
95 bool readGZIPHeader;
97 /// <summary>
98 /// Creates a GzipInputStream with the default buffer size
99 /// </summary>
100 /// <param name="baseInputStream">
101 /// The stream to read compressed data from (baseInputStream GZIP format)
102 /// </param>
103 public GZipInputStream(Stream baseInputStream) : this(baseInputStream, 4096)
107 /// <summary>
108 /// Creates a GZIPInputStream with the specified buffer size
109 /// </summary>
110 /// <param name="baseInputStream">
111 /// The stream to read compressed data from (baseInputStream GZIP format)
112 /// </param>
113 /// <param name="size">
114 /// Size of the buffer to use
115 /// </param>
116 public GZipInputStream(Stream baseInputStream, int size) : base(baseInputStream, new Inflater(true), size)
120 /// <summary>
121 /// Reads uncompressed data into an array of bytes
122 /// </summary>
123 /// <param name="buf">
124 /// the buffer to read uncompressed data into
125 /// </param>
126 /// <param name="offset">
127 /// the offset indicating where the data should be placed
128 /// </param>
129 /// <param name="len">
130 /// the number of uncompressed bytes to be read
131 /// </param>
132 public override int Read(byte[] buf, int offset, int len)
134 // We first have to slurp baseInputStream the GZIP header, then we feed all the
135 // rest of the data to the superclass.
137 // As we do that we continually update the CRC32. Once the data is
138 // finished, we check the CRC32
140 // This means we don't need our own buffer, as everything is done
141 // baseInputStream the superclass.
142 if (!readGZIPHeader) {
143 ReadHeader();
146 if (eos) {
147 return 0;
150 // System.err.println("GZIPIS.read(byte[], off, len ... " + offset + " and len " + len);
151 //We don't have to read the header, so we just grab data from the superclass
152 int numRead = base.Read(buf, offset, len);
153 if (numRead > 0) {
154 crc.Update(buf, offset, numRead);
157 if (inf.IsFinished) {
158 ReadFooter();
160 return numRead;
163 private void ReadHeader()
165 /* 1. Check the two magic bytes */
166 Crc32 headCRC = new Crc32();
167 int magic = baseInputStream.ReadByte();
168 if (magic < 0) {
169 eos = true;
170 return;
172 headCRC.Update(magic);
173 if (magic != (GZipConstants.GZIP_MAGIC >> 8)) {
174 throw new IOException("Error baseInputStream GZIP header, first byte doesn't match");
177 magic = baseInputStream.ReadByte();
178 if (magic != (GZipConstants.GZIP_MAGIC & 0xFF)) {
179 throw new IOException("Error baseInputStream GZIP header, second byte doesn't match");
181 headCRC.Update(magic);
183 /* 2. Check the compression type (must be 8) */
184 int CM = baseInputStream.ReadByte();
185 if (CM != 8) {
186 throw new IOException("Error baseInputStream GZIP header, data not baseInputStream deflate format");
188 headCRC.Update(CM);
190 /* 3. Check the flags */
191 int flags = baseInputStream.ReadByte();
192 if (flags < 0) {
193 throw new Exception("Early EOF baseInputStream GZIP header");
195 headCRC.Update(flags);
197 /* This flag byte is divided into individual bits as follows:
199 bit 0 FTEXT
200 bit 1 FHCRC
201 bit 2 FEXTRA
202 bit 3 FNAME
203 bit 4 FCOMMENT
204 bit 5 reserved
205 bit 6 reserved
206 bit 7 reserved
209 /* 3.1 Check the reserved bits are zero */
211 if ((flags & 0xd0) != 0) {
212 throw new IOException("Reserved flag bits baseInputStream GZIP header != 0");
215 /* 4.-6. Skip the modification time, extra flags, and OS type */
216 for (int i=0; i< 6; i++) {
217 int readByte = baseInputStream.ReadByte();
218 if (readByte < 0) {
219 throw new Exception("Early EOF baseInputStream GZIP header");
221 headCRC.Update(readByte);
224 /* 7. Read extra field */
225 if ((flags & GZipConstants.FEXTRA) != 0) {
226 /* Skip subfield id */
227 for (int i=0; i< 2; i++) {
228 int readByte = baseInputStream.ReadByte();
229 if (readByte < 0) {
230 throw new Exception("Early EOF baseInputStream GZIP header");
232 headCRC.Update(readByte);
234 if (baseInputStream.ReadByte() < 0 || baseInputStream.ReadByte() < 0) {
235 throw new Exception("Early EOF baseInputStream GZIP header");
238 int len1, len2, extraLen;
239 len1 = baseInputStream.ReadByte();
240 len2 = baseInputStream.ReadByte();
241 if ((len1 < 0) || (len2 < 0)) {
242 throw new Exception("Early EOF baseInputStream GZIP header");
244 headCRC.Update(len1);
245 headCRC.Update(len2);
247 extraLen = (len1 << 8) | len2;
248 for (int i = 0; i < extraLen;i++) {
249 int readByte = baseInputStream.ReadByte();
250 if (readByte < 0)
252 throw new Exception("Early EOF baseInputStream GZIP header");
254 headCRC.Update(readByte);
258 /* 8. Read file name */
259 if ((flags & GZipConstants.FNAME) != 0) {
260 int readByte;
261 while ( (readByte = baseInputStream.ReadByte()) > 0) {
262 headCRC.Update(readByte);
264 if (readByte < 0) {
265 throw new Exception("Early EOF baseInputStream GZIP file name");
267 headCRC.Update(readByte);
270 /* 9. Read comment */
271 if ((flags & GZipConstants.FCOMMENT) != 0) {
272 int readByte;
273 while ( (readByte = baseInputStream.ReadByte()) > 0) {
274 headCRC.Update(readByte);
277 if (readByte < 0) {
278 throw new Exception("Early EOF baseInputStream GZIP comment");
280 headCRC.Update(readByte);
283 /* 10. Read header CRC */
284 if ((flags & GZipConstants.FHCRC) != 0) {
285 int tempByte;
286 int crcval = baseInputStream.ReadByte();
287 if (crcval < 0) {
288 throw new Exception("Early EOF baseInputStream GZIP header");
291 tempByte = baseInputStream.ReadByte();
292 if (tempByte < 0) {
293 throw new Exception("Early EOF baseInputStream GZIP header");
296 crcval = (crcval << 8) | tempByte;
297 if (crcval != ((int) headCRC.Value & 0xffff)) {
298 throw new IOException("Header CRC value mismatch");
302 readGZIPHeader = true;
303 //System.err.println("Read GZIP header");
306 private void ReadFooter()
308 byte[] footer = new byte[8];
309 int avail = inf.RemainingInput;
310 if (avail > 8) {
311 avail = 8;
313 System.Array.Copy(buf, len - inf.RemainingInput, footer, 0, avail);
314 int needed = 8 - avail;
315 while (needed > 0) {
316 int count = baseInputStream.Read(footer, 8-needed, needed);
317 if (count <= 0) {
318 throw new Exception("Early EOF baseInputStream GZIP footer");
320 needed -= count; //Jewel Jan 16
322 int crcval = (footer[0] & 0xff) | ((footer[1] & 0xff) << 8) | ((footer[2] & 0xff) << 16) | (footer[3] << 24);
323 if (crcval != (int) crc.Value) {
324 throw new IOException("GZIP crc sum mismatch, theirs \"" + crcval + "\" and ours \"" + (int) crc.Value);
326 int total = (footer[4] & 0xff) | ((footer[5] & 0xff) << 8) | ((footer[6] & 0xff) << 16) | (footer[7] << 24);
327 if (total != inf.TotalOut) {
328 throw new IOException("Number of bytes mismatch");
330 /* XXX Should we support multiple members.
331 * Difficult, since there may be some bytes still baseInputStream buf
333 eos = true;