1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package edu.internet2.middleware.grouperInstallerExt.org.apache.commons.compress.compressors.gzip;
20
21 import java.io.ByteArrayOutputStream;
22 import java.io.IOException;
23 import java.io.EOFException;
24 import java.io.InputStream;
25 import java.io.DataInputStream;
26 import java.io.BufferedInputStream;
27 import java.util.zip.DataFormatException;
28 import java.util.zip.Deflater;
29 import java.util.zip.Inflater;
30 import java.util.zip.CRC32;
31
32 import edu.internet2.middleware.grouperInstallerExt.org.apache.commons.compress.compressors.CompressorInputStream;
33 import edu.internet2.middleware.grouperInstallerExt.org.apache.commons.compress.utils.CharsetNames;
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 public class GzipCompressorInputStream extends CompressorInputStream {
51
52
53 private static final int FHCRC = 0x02;
54 private static final int FEXTRA = 0x04;
55 private static final int FNAME = 0x08;
56 private static final int FCOMMENT = 0x10;
57 private static final int FRESERVED = 0xE0;
58
59
60 private final InputStream in;
61
62
63 private final boolean decompressConcatenated;
64
65
66 private final byte[] buf = new byte[8192];
67
68
69 private int bufUsed = 0;
70
71
72 private Inflater inf = new Inflater(true);
73
74
75 private final CRC32 crc = new CRC32();
76
77
78 private boolean endReached = false;
79
80
81 private final byte[] oneByte = new byte[1];
82
83 private final GzipParametersre/grouperInstallerExt/org/apache/commons/compress/compressors/gzip/GzipParameters.html#GzipParameters">GzipParameters parameters = new GzipParameters();
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98 public GzipCompressorInputStream(InputStream inputStream)
99 throws IOException {
100 this(inputStream, false);
101 }
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123 public GzipCompressorInputStream(InputStream inputStream,
124 boolean decompressConcatenated)
125 throws IOException {
126
127
128 if (inputStream.markSupported()) {
129 in = inputStream;
130 } else {
131 in = new BufferedInputStream(inputStream);
132 }
133
134 this.decompressConcatenated = decompressConcatenated;
135 init(true);
136 }
137
138
139
140
141
142
143
144 public GzipParameters getMetaData() {
145 return parameters;
146 }
147
148 private boolean init(boolean isFirstMember) throws IOException {
149 assert isFirstMember || decompressConcatenated;
150
151
152 int magic0 = in.read();
153 int magic1 = in.read();
154
155
156
157 if (magic0 == -1 && !isFirstMember) {
158 return false;
159 }
160
161 if (magic0 != 31 || magic1 != 139) {
162 throw new IOException(isFirstMember
163 ? "Input is not in the .gz format"
164 : "Garbage after a valid .gz stream");
165 }
166
167
168 DataInputStream inData = new DataInputStream(in);
169 int method = inData.readUnsignedByte();
170 if (method != Deflater.DEFLATED) {
171 throw new IOException("Unsupported compression method "
172 + method + " in the .gz header");
173 }
174
175 int flg = inData.readUnsignedByte();
176 if ((flg & FRESERVED) != 0) {
177 throw new IOException(
178 "Reserved flags are set in the .gz header");
179 }
180
181 parameters.setModificationTime(readLittleEndianInt(inData) * 1000);
182 switch (inData.readUnsignedByte()) {
183 case 2:
184 parameters.setCompressionLevel(Deflater.BEST_COMPRESSION);
185 break;
186 case 4:
187 parameters.setCompressionLevel(Deflater.BEST_SPEED);
188 break;
189 default:
190
191 break;
192 }
193 parameters.setOperatingSystem(inData.readUnsignedByte());
194
195
196 if ((flg & FEXTRA) != 0) {
197 int xlen = inData.readUnsignedByte();
198 xlen |= inData.readUnsignedByte() << 8;
199
200
201
202
203 while (xlen-- > 0) {
204 inData.readUnsignedByte();
205 }
206 }
207
208
209 if ((flg & FNAME) != 0) {
210 parameters.setFilename(new String(readToNull(inData),
211 CharsetNames.ISO_8859_1));
212 }
213
214
215 if ((flg & FCOMMENT) != 0) {
216 parameters.setComment(new String(readToNull(inData),
217 CharsetNames.ISO_8859_1));
218 }
219
220
221
222
223
224
225 if ((flg & FHCRC) != 0) {
226 inData.readShort();
227 }
228
229
230 inf.reset();
231 crc.reset();
232
233 return true;
234 }
235
236 private byte[] readToNull(DataInputStream inData) throws IOException {
237 ByteArrayOutputStream bos = new ByteArrayOutputStream();
238 int b = 0;
239 while ((b = inData.readUnsignedByte()) != 0x00) {
240 bos.write(b);
241 }
242 return bos.toByteArray();
243 }
244
245 private long readLittleEndianInt(DataInputStream inData) throws IOException {
246 return inData.readUnsignedByte()
247 | (inData.readUnsignedByte() << 8)
248 | (inData.readUnsignedByte() << 16)
249 | (((long) inData.readUnsignedByte()) << 24);
250 }
251
252 @Override
253 public int read() throws IOException {
254 return read(oneByte, 0, 1) == -1 ? -1 : oneByte[0] & 0xFF;
255 }
256
257
258
259
260
261
262 @Override
263 public int read(byte[] b, int off, int len) throws IOException {
264 if (endReached) {
265 return -1;
266 }
267
268 int size = 0;
269
270 while (len > 0) {
271 if (inf.needsInput()) {
272
273
274 in.mark(buf.length);
275
276 bufUsed = in.read(buf);
277 if (bufUsed == -1) {
278 throw new EOFException();
279 }
280
281 inf.setInput(buf, 0, bufUsed);
282 }
283
284 int ret;
285 try {
286 ret = inf.inflate(b, off, len);
287 } catch (DataFormatException e) {
288 throw new IOException("Gzip-compressed data is corrupt");
289 }
290
291 crc.update(b, off, ret);
292 off += ret;
293 len -= ret;
294 size += ret;
295 count(ret);
296
297 if (inf.finished()) {
298
299
300
301
302
303 in.reset();
304
305 int skipAmount = bufUsed - inf.getRemaining();
306 if (in.skip(skipAmount) != skipAmount) {
307 throw new IOException();
308 }
309
310 bufUsed = 0;
311
312 DataInputStream inData = new DataInputStream(in);
313
314
315 long crcStored = readLittleEndianInt(inData);
316
317 if (crcStored != crc.getValue()) {
318 throw new IOException("Gzip-compressed data is corrupt "
319 + "(CRC32 error)");
320 }
321
322
323 long isize = readLittleEndianInt(inData);
324
325 if (isize != (inf.getBytesWritten() & 0xffffffffl)) {
326 throw new IOException("Gzip-compressed data is corrupt"
327 + "(uncompressed size mismatch)");
328 }
329
330
331 if (!decompressConcatenated || !init(false)) {
332 inf.end();
333 inf = null;
334 endReached = true;
335 return size == 0 ? -1 : size;
336 }
337 }
338 }
339
340 return size;
341 }
342
343
344
345
346
347
348
349
350
351
352 public static boolean matches(byte[] signature, int length) {
353
354 if (length < 2) {
355 return false;
356 }
357
358 if (signature[0] != 31) {
359 return false;
360 }
361
362 if (signature[1] != -117) {
363 return false;
364 }
365
366 return true;
367 }
368
369
370
371
372
373
374 @Override
375 public void close() throws IOException {
376 if (inf != null) {
377 inf.end();
378 inf = null;
379 }
380
381 if (this.in != System.in) {
382 this.in.close();
383 }
384 }
385 }