import java.util.*; import java.util.zip.*; import java.util.List; import java.util.regex.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; import java.util.concurrent.locks.*; import javax.swing.*; import javax.swing.event.*; import javax.swing.text.*; import javax.swing.table.*; import java.io.*; import java.net.*; import java.lang.reflect.*; import java.lang.ref.*; import java.lang.management.*; import java.security.*; import java.security.spec.*; import java.awt.*; import java.awt.event.*; import java.awt.image.*; import javax.imageio.*; import java.math.*; class main { static class GZIPInputStream_relaxed extends InflaterInputStream_relaxed { /** * CRC-32 for uncompressed data. */ protected CRC32 crc = new CRC32(); /** * Indicates end of input stream. */ protected boolean eos = false; /** * Creates a new input stream with the specified buffer size. * @param in the input stream * @param size the input buffer size * * @throws ZipException if a GZIP format error has occurred or the * compression method used is unsupported * @throws IOException if an I/O error has occurred * @throws IllegalArgumentException if {@code size <= 0} */ public GZIPInputStream_relaxed(InputStream in, int size) throws IOException { super(in, new Inflater(true), size); usesDefaultInflater = true; readHeader(in); } /** * Creates a new input stream with a default buffer size. * @param in the input stream * * @throws ZipException if a GZIP format error has occurred or the * compression method used is unsupported * @throws IOException if an I/O error has occurred */ public GZIPInputStream_relaxed(InputStream in) throws IOException { this(in, 512); } /** * Reads uncompressed data into an array of bytes. If {@code len} is not * zero, the method will block until some input can be decompressed; otherwise, * no bytes are read and {@code 0} is returned. * @param buf the buffer into which the data is read * @param off the start offset in the destination array {@code b} * @param len the maximum number of bytes read * @return the actual number of bytes read, or -1 if the end of the * compressed input stream is reached * * @throws NullPointerException If {@code buf} is {@code null}. * @throws IndexOutOfBoundsException If {@code off} is negative, * {@code len} is negative, or {@code len} is greater than * {@code buf.length - off} * @throws ZipException if the compressed input data is corrupt. * @throws IOException if an I/O error has occurred. * */ public int read(byte[] buf, int off, int len) throws IOException { ensureOpen(); if (eos) { return -1; } int n = super.read(buf, off, len); if (n == -1) { if (readTrailer()) eos = true; else return this.read(buf, off, len); } else { crc.update(buf, off, n); } return n; } /** * Closes this input stream and releases any system resources associated * with the stream. * @throws IOException if an I/O error has occurred */ public void close() throws IOException { if (!closed) { super.close(); eos = true; closed = true; } } /** * GZIP header magic number. */ public static final int GZIP_MAGIC = 0x8b1f; /* * File header flags. */ private static final int FTEXT = 1; // Extra text private static final int FHCRC = 2; // Header CRC private static final int FEXTRA = 4; // Extra field private static final int FNAME = 8; // File name private static final int FCOMMENT = 16; // File comment /* * Reads GZIP member header and returns the total byte number * of this member header. */ private int readHeader(InputStream this_in) throws IOException { CheckedInputStream in = new CheckedInputStream(this_in, crc); crc.reset(); // Check header magic if (readUShort(in) != GZIP_MAGIC) { throw new ZipException("Not in GZIP format"); } // Check compression method if (readUByte(in) != 8) { throw new ZipException("Unsupported compression method"); } // Read flags int flg = readUByte(in); // Skip MTIME, XFL, and OS fields skipBytes(in, 6); int n = 2 + 2 + 6; // Skip optional extra field if ((flg & FEXTRA) == FEXTRA) { int m = readUShort(in); skipBytes(in, m); n += m + 2; } // Skip optional file name if ((flg & FNAME) == FNAME) { do { n++; } while (readUByte(in) != 0); } // Skip optional file comment if ((flg & FCOMMENT) == FCOMMENT) { do { n++; } while (readUByte(in) != 0); } // Check optional header CRC if ((flg & FHCRC) == FHCRC) { int v = (int)crc.getValue() & 0xffff; if (readUShort(in) != v) { throw new ZipException("Corrupt GZIP header"); } n += 2; } crc.reset(); return n; } /* * Reads GZIP member trailer and returns true if the eos * reached, false if there are more (concatenated gzip * data set) */ private boolean readTrailer() throws IOException { InputStream in = this.in; int n = inf.getRemaining(); if (n > 0) { in = new SequenceInputStream( new ByteArrayInputStream(buf, len - n, n), new FilterInputStream(in) { public void close() throws IOException {} }); } // Uses left-to-right evaluation order if ((readUInt(in) != crc.getValue()) || // rfc1952; ISIZE is the input size modulo 2^32 (readUInt(in) != (inf.getBytesWritten() & 0xffffffffL))) throw new ZipException("Corrupt GZIP trailer"); // If there are more bytes available in "in" or // the leftover in the "inf" is > 26 bytes: // this.trailer(8) + next.header.min(10) + next.trailer(8) // try concatenated case if (this.in.available() > 0 || n > 26) { int m = 8; // this.trailer try { m += readHeader(in); // next.header } catch (IOException ze) { return true; // ignore any malformed, do nothing } inf.reset(); if (n > m) inf.setInput(buf, len - n + m, n - m); return false; } return true; } /* * Reads unsigned integer in Intel byte order. */ private long readUInt(InputStream in) throws IOException { long s = readUShort(in); return ((long)readUShort(in) << 16) | s; } /* * Reads unsigned short in Intel byte order. */ private int readUShort(InputStream in) throws IOException { int b = readUByte(in); return (readUByte(in) << 8) | b; } /* * Reads unsigned byte. */ private int readUByte(InputStream in) throws IOException { int b = in.read(); if (b == -1) { throw new EOFException(); } if (b < -1 || b > 255) { // Report on this.in, not argument in; see read{Header, Trailer}. throw new IOException(this.in.getClass().getName() + ".read() returned value out of range -1..255: " + b); } return b; } private byte[] tmpbuf = new byte[128]; /* * Skips bytes of input data blocking until all bytes are skipped. * Does not assume that the input stream is capable of seeking. */ private void skipBytes(InputStream in, int n) throws IOException { while (n > 0) { int len = in.read(tmpbuf, 0, n < tmpbuf.length ? n : tmpbuf.length); if (len == -1) { throw new EOFException(); } n -= len; } } } static class InflaterInputStream_relaxed extends FilterInputStream { /** * Decompressor for this stream. */ protected Inflater inf; /** * Input buffer for decompression. */ protected byte[] buf; /** * Length of input buffer. */ protected int len; boolean closed = false; // this flag is set to true after EOF has reached private boolean reachEOF = false; /** * Check to make sure that this stream has not been closed */ void ensureOpen() throws IOException { if (closed) { throw new IOException("Stream closed"); } } /** * Creates a new input stream with the specified decompressor and * buffer size. * @param in the input stream * @param inf the decompressor ("inflater") * @param size the input buffer size * @throws IllegalArgumentException if {@code size <= 0} */ public InflaterInputStream_relaxed(InputStream in, Inflater inf, int size) { super(in); if (in == null || inf == null) { throw new NullPointerException(); } else if (size <= 0) { throw new IllegalArgumentException("buffer size <= 0"); } this.inf = inf; buf = new byte[size]; } /** * Creates a new input stream with the specified decompressor and a * default buffer size. * @param in the input stream * @param inf the decompressor ("inflater") */ public InflaterInputStream_relaxed(InputStream in, Inflater inf) { this(in, inf, 512); } boolean usesDefaultInflater = false; /** * Creates a new input stream with a default decompressor and buffer size. * @param in the input stream */ public InflaterInputStream_relaxed(InputStream in) { this(in, new Inflater()); usesDefaultInflater = true; } private byte[] singleByteBuf = new byte[1]; /** * Reads a byte of uncompressed data. This method will block until * enough input is available for decompression. * @return the byte read, or -1 if end of compressed input is reached * @throws IOException if an I/O error has occurred */ public int read() throws IOException { ensureOpen(); return read(singleByteBuf, 0, 1) == -1 ? -1 : Byte.toUnsignedInt(singleByteBuf[0]); } /** * Reads uncompressed data into an array of bytes. If {@code len} is not * zero, the method will block until some input can be decompressed; otherwise, * no bytes are read and {@code 0} is returned. * @param b the buffer into which the data is read * @param off the start offset in the destination array {@code b} * @param len the maximum number of bytes read * @return the actual number of bytes read, or -1 if the end of the * compressed input is reached or a preset dictionary is needed * @throws NullPointerException If {@code b} is {@code null}. * @throws IndexOutOfBoundsException If {@code off} is negative, * {@code len} is negative, or {@code len} is greater than * {@code b.length - off} * @throws ZipException if a ZIP format error has occurred * @throws IOException if an I/O error has occurred */ public int read(byte[] b, int off, int len) throws IOException { ensureOpen(); if (b == null) { throw new NullPointerException(); } else if (off < 0 || len < 0 || len > b.length - off) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } try { int n; while ((n = inf.inflate(b, off, len)) == 0) { if (inf.finished() || inf.needsDictionary()) { reachEOF = true; return -1; } if (inf.needsInput()) { if (!fill()) return -1; } } return n; } catch (DataFormatException e) { String s = e.getMessage(); throw new ZipException(s != null ? s : "Invalid ZLIB data format"); } } /** * Returns 0 after EOF has been reached, otherwise always return 1. *

* Programs should not count on this method to return the actual number * of bytes that could be read without blocking. * * @return 1 before EOF and 0 after EOF. * @throws IOException if an I/O error occurs. * */ public int available() throws IOException { ensureOpen(); if (reachEOF) { return 0; } else if (inf.finished()) { // the end of the compressed data stream has been reached reachEOF = true; return 0; } else { return 1; } } private byte[] b = new byte[512]; /** * Skips specified number of bytes of uncompressed data. * @param n the number of bytes to skip * @return the actual number of bytes skipped. * @throws IOException if an I/O error has occurred * @throws IllegalArgumentException if {@code n < 0} */ public long skip(long n) throws IOException { if (n < 0) { throw new IllegalArgumentException("negative skip length"); } ensureOpen(); int max = (int)Math.min(n, Integer.MAX_VALUE); int total = 0; while (total < max) { int len = max - total; if (len > b.length) { len = b.length; } len = read(b, 0, len); if (len == -1) { reachEOF = true; break; } total += len; } return total; } /** * Closes this input stream and releases any system resources associated * with the stream. * @throws IOException if an I/O error has occurred */ public void close() throws IOException { if (!closed) { if (usesDefaultInflater) inf.end(); in.close(); closed = true; } } /** * Fills input buffer with more data to decompress. * @throws IOException if an I/O error has occurred * @return true if not at end of stream */ protected boolean fill() throws IOException { ensureOpen(); len = in.read(buf, 0, buf.length); if (len == -1) return false; inf.setInput(buf, 0, len); return true; } /** * Tests if this input stream supports the {@code mark} and * {@code reset} methods. The {@code markSupported} * method of {@code InflaterInputStream_relaxed} returns * {@code false}. * * @return a {@code boolean} indicating if this stream type supports * the {@code mark} and {@code reset} methods. * @see java.io.InputStream#mark(int) * @see java.io.InputStream#reset() */ public boolean markSupported() { return false; } /** * Marks the current position in this input stream. * *

The {@code mark} method of {@code InflaterInputStream_relaxed} * does nothing. * * @param readlimit the maximum limit of bytes that can be read before * the mark position becomes invalid. * @see java.io.InputStream#reset() */ public synchronized void mark(int readlimit) { } /** * Repositions this stream to the position at the time the * {@code mark} method was last called on this input stream. * *

The method {@code reset} for class * {@code InflaterInputStream_relaxed} does nothing except throw an * {@code IOException}. * * @throws IOException if this method is invoked. * @see java.io.InputStream#mark(int) * @see java.io.IOException */ public synchronized void reset() throws IOException { throw new IOException("mark/reset not supported"); } } }