/* * This file is part of the OWASP Proxy, a free intercepting proxy library. * Copyright (C) 2008-2010 Rogan Dawes <rogan@dawes.za.net> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to: * The Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ package org.owasp.proxy.io; import java.io.IOException; import java.io.InputStream; import java.util.zip.Deflater; public class GzipInputStream extends DeflaterInputStream { protected CRC32InputStream crc; /* * GZIP header magic number. */ private final static int GZIP_MAGIC = 0x8b1f; private boolean eof = false; private int header = 0; private int trailer = -1; public GzipInputStream(InputStream in) { this(in, 512); } public GzipInputStream(InputStream in, int size) { // this is a bit of a hack. We HAVE to calculate the CRC on // uncompressed data, but reading from super gives Deflated data. // So wrap the original InputStream in a CRC-calculating InputStream // before we call the super.constructor. // To get our own reference to it, we have to refer to super.in, and // cast it back super(new CRC32InputStream(in), new Deflater( Deflater.DEFAULT_COMPRESSION, true), size); crc = (CRC32InputStream) super.in; } public int read() throws IOException { return super.read(); } /* * (non-Javadoc) * * @see java.util.zip.DeflaterInputStream#read(byte[], int, int) */ @Override public int read(byte[] b, int off, int len) throws IOException { int read = 0; if (header < HEADER.length) { read += addHeader(b, off, len); } if (!eof) { int got; while (read < len && (got = super.read(b, off + read, len - read)) > -1) { read += got; } if (read < len) eof = true; } if (eof) if (trailer < TRAILER.length) { read += addTrailer(b, off + read, len - read); } else { return -1; } return read; } private int addHeader(byte[] b, int off, int len) { int l = Math.min(HEADER.length - header, len); if (l > 0) { System.arraycopy(HEADER, header, b, off, l); header += l; } return l; } private int addTrailer(byte[] b, int off, int len) throws IOException { if (trailer == -1) { makeTrailer(); trailer = 0; } int l = Math.min(TRAILER.length - trailer, len); if (l > 0) { System.arraycopy(TRAILER, trailer, b, off, l); trailer += l; } return l; } /* * Writes GZIP member header. */ private final static byte[] HEADER = { (byte) GZIP_MAGIC, // Magic number // (short) (byte) (GZIP_MAGIC >> 8), // Magic number (short) Deflater.DEFLATED, // Compression method (CM) 0, // Flags (FLG) 0, // Modification time MTIME (int) 0, // Modification time MTIME (int) 0, // Modification time MTIME (int) 0, // Modification time MTIME (int) 0, // Extra flags (XFLG) 0 // Operating system (OS) }; private byte[] TRAILER = new byte[8]; /* * Writes GZIP member trailer to a byte array, starting at a given offset. */ private void makeTrailer() throws IOException { writeInt((int) crc.getValue(), TRAILER, 0); // CRC-32 of uncompr. data writeInt(def.getTotalIn(), TRAILER, 4); // Number of uncompr. bytes } /* * Writes integer in Intel byte order to a byte array, starting at a given offset. */ private void writeInt(int i, byte[] buf, int offset) throws IOException { writeShort(i & 0xffff, buf, offset); writeShort((i >> 16) & 0xffff, buf, offset + 2); } /* * Writes short integer in Intel byte order to a byte array, starting at a given offset */ private void writeShort(int s, byte[] buf, int offset) throws IOException { buf[offset] = (byte) (s & 0xff); buf[offset + 1] = (byte) ((s >> 8) & 0xff); } }