2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 package java.util.zip;
20 import java.io.EOFException;
21 import java.io.IOException;
22 import java.io.InputStream;
24 import org.apache.harmony.archive.internal.nls.Messages;
27 * The {@code GZIPInputStream} class is used to read data stored in the GZIP
28 * format, reading and decompressing GZIP data from the underlying stream into
31 public class GZIPInputStream extends InflaterInputStream {
33 private static final int FCOMMENT = 16;
35 private static final int FEXTRA = 4;
37 private static final int FHCRC = 2;
39 private static final int FNAME = 8;
42 * The magic header for the GZIP format.
44 public final static int GZIP_MAGIC = 0x8b1f;
47 * The checksum algorithm used when handling uncompressed data.
49 protected CRC32 crc = new CRC32();
52 * Indicates the end of the input stream.
54 protected boolean eos = false;
57 * Construct a {@code GZIPInputStream} to read from GZIP data from the
61 * the {@code InputStream} to read data from.
63 * if an {@code IOException} occurs.
65 public GZIPInputStream(InputStream is) throws IOException {
70 * Construct a {@code GZIPInputStream} to read from GZIP data from the
71 * underlying stream. Set the internal buffer size to {@code size}.
74 * the {@code InputStream} to read data from.
76 * the internal read buffer size.
78 * if an {@code IOException} occurs.
80 public GZIPInputStream(InputStream is, int size) throws IOException {
81 super(is, new Inflater(true), size);
82 byte[] header = new byte[10];
83 readFully(header, 0, header.length);
84 if (getShort(header, 0) != GZIP_MAGIC) {
85 throw new IOException(Messages.getString("archive.1F")); //$NON-NLS-1$;
87 int flags = header[3];
88 boolean hcrc = (flags & FHCRC) != 0;
90 crc.update(header, 0, header.length);
92 if ((flags & FEXTRA) != 0) {
93 readFully(header, 0, 2);
95 crc.update(header, 0, 2);
97 int length = getShort(header, 0);
99 int max = length > buf.length ? buf.length : length;
100 int result = in.read(buf, 0, max);
102 throw new EOFException();
105 crc.update(buf, 0, result);
110 if ((flags & FNAME) != 0) {
111 readZeroTerminated(hcrc);
113 if ((flags & FCOMMENT) != 0) {
114 readZeroTerminated(hcrc);
117 readFully(header, 0, 2);
118 int crc16 = getShort(header, 0);
119 if ((crc.getValue() & 0xffff) != crc16) {
120 throw new IOException(Messages.getString("archive.20")); //$NON-NLS-1$
127 * Closes this stream and any underlying streams.
130 public void close() throws IOException {
135 private long getLong(byte[] buffer, int off) {
137 l |= (buffer[off] & 0xFF);
138 l |= (buffer[off + 1] & 0xFF) << 8;
139 l |= (buffer[off + 2] & 0xFF) << 16;
140 l |= ((long) (buffer[off + 3] & 0xFF)) << 24;
144 private int getShort(byte[] buffer, int off) {
145 return (buffer[off] & 0xFF) | ((buffer[off + 1] & 0xFF) << 8);
149 * Reads and decompresses GZIP data from the underlying stream into the
153 * Buffer to receive data
155 * Offset in buffer to store data
157 * Number of bytes to read
160 public int read(byte[] buffer, int off, int nbytes) throws IOException {
162 throw new IOException(Messages.getString("archive.1E")); //$NON-NLS-1$
167 // avoid int overflow, check null buffer
168 if (off <= buffer.length && nbytes >= 0 && off >= 0
169 && buffer.length - off >= nbytes) {
170 int val = super.read(buffer, off, nbytes);
172 crc.update(buffer, off, val);
175 // Get non-compressed bytes read by fill
176 int size = inf.getRemaining();
177 final int trailerSize = 8; // crc (4 bytes) + total out (4
179 byte[] b = new byte[trailerSize];
180 int copySize = (size > trailerSize) ? trailerSize : size;
182 System.arraycopy(buf, len - size, b, 0, copySize);
183 readFully(b, copySize, trailerSize - copySize);
185 if (getLong(b, 0) != crc.getValue()) {
186 throw new IOException(Messages.getString("archive.20")); //$NON-NLS-1$
188 if ((int) getLong(b, 4) != inf.getTotalOut()) {
189 throw new IOException(Messages.getString("archive.21")); //$NON-NLS-1$
194 throw new ArrayIndexOutOfBoundsException();
197 private void readFully(byte[] buffer, int offset, int length)
201 result = in.read(buffer, offset, length);
203 throw new EOFException();
210 private void readZeroTerminated(boolean hcrc) throws IOException {
212 while ((result = in.read()) > 0) {
218 throw new EOFException();