/* * Copyright (C) 2010 IsmAvatar <IsmAvatar@gmail.com> * * This file is part of LateralGM. * LateralGM is free software and comes with ABSOLUTELY NO WARRANTY. * See LICENSE for details. */ package org.lateralgm.file; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.util.zip.Inflater; import java.util.zip.InflaterInputStream; /** * This class implements a stream filter for uncompressing data in the * "deflate" compression format, limited to a certain given number of compressed bytes. * * @see Inflater * @author IsmAvatar */ public class LimitedInflaterInputStream extends InflaterInputStream { protected long limit; private boolean closed = false; /** * Creates a new input stream with a default decompressor and buffer size, * limited to reading up to a given number of compressed bytes. * @param in the input stream * @param limit the maximum number of compressed bytes that may be read */ public LimitedInflaterInputStream(InputStream in, long limit) { super(in,new Inflater(),512); this.limit = limit; } /** * Returns 0 if the end of file has been reached, otherwise returns * the remaining compressed bytes left until the limit is reached. * <p> * Programs should not count on this method to return the number * of bytes that could be read without blocking. * * @return remaining compressed bytes left until limit reached * @exception IOException if an I/O error occurs. */ public int available() throws IOException { ensureOpen(); if (super.available() == 0) return 0; return (int) Math.min(limit,Integer.MAX_VALUE); } private void ensureOpen() throws IOException { if (closed) throw new IOException("Stream closed"); } /** * Skips the remaining compressed bytes in this stream until limit is reached, * and releases any system resources associated with the inflater. * Essentially closes this input stream without closing the underlying input stream. * @throws IOException if an I/O error has occurred */ public void finish() throws IOException { if (!closed) { while (limit > 0 && in.available() > 0) limit -= in.skip(limit); inf.end(); //default inflater assumed closed = true; } } /** * Closes this input stream, closes the underlying input stream, * and releases any system resources associated with the stream. * @exception IOException if an I/O error has occurred */ public void close() throws IOException { if (!closed) { inf.end(); //default inflater assumed in.close(); closed = true; } } /** * Fills input buffer with more data to decompress, not exceeding the limit. * @exception IOException if an I/O error has occurred */ protected void fill() throws IOException { ensureOpen(); int len = in.read(buf,0,(int) Math.min(limit,buf.length)); if (len == -1) throw new EOFException("Unexpected end of ZLIB input stream"); limit -= len; inf.setInput(buf,0,len); } public long getLimit() { return limit; } }