001    /*
002     * This file is part of muCommander, http://www.mucommander.com
003     * Copyright (C) 2002-2008 Maxence Bernard
004     *
005     * muCommander is free software; you can redistribute it and/or modify
006     * it under the terms of the GNU General Public License as published by
007     * the Free Software Foundation; either version 3 of the License, or
008     * (at your option) any later version.
009     *
010     * muCommander is distributed in the hope that it will be useful,
011     * but WITHOUT ANY WARRANTY; without even the implied warranty of
012     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013     * GNU General Public License for more details.
014     *
015     * You should have received a copy of the GNU General Public License
016     * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017     */
018    
019    package com.mucommander.io;
020    
021    import java.io.IOException;
022    import java.io.InputStream;
023    
024    /**
025     * An InputStream that has a set limit to the number of bytes that can be read from it before the EOF is reached.
026     * The limit will have no effect if it is higher than the number of remaining bytes in the underlying stream.
027     *
028     * <p>This class is particularly useful for reading archive formats which contain concatenated files.
029     *
030     * @author Maxence Bernard
031     * @see com.mucommander.file.impl.ar.ArArchiveFile
032     */
033    public class ByteLimitInputStream extends InputStream {
034    
035        private InputStream in;
036        private long bytesRemaining;
037    
038        public ByteLimitInputStream(InputStream in, long size) {
039            this.in = in;
040            this.bytesRemaining = size;
041        }
042    
043    
044        ////////////////////////////////
045        // InputStream implementation //
046        ////////////////////////////////
047    
048        public int read() throws IOException {
049            if(bytesRemaining<=0)
050                return -1;  // EOF reached
051    
052            int i = in.read();
053            if(i>0)
054                this.bytesRemaining--;
055    
056            return i;
057        }
058    
059        public int read(byte b[]) throws IOException {
060            return read(b, 0, b.length);
061        }
062    
063        public int read(byte b[], int off, int len) throws IOException {
064            if(bytesRemaining<=0)
065                return -1;  // EOF reached
066    
067            int nbRead = in.read(b, off, Math.min(len, (int)this.bytesRemaining));
068            if(nbRead>0)
069                this.bytesRemaining -= nbRead;
070    
071            return nbRead;
072        }
073    
074    
075        public long skip(long n) throws IOException {
076            if(bytesRemaining<=0)
077                return -1;  // EOF reached
078    
079            long nbSkipped = in.skip(Math.min(n, (int)this.bytesRemaining));
080            if(nbSkipped>0)
081                this.bytesRemaining -= nbSkipped;
082    
083            return nbSkipped;
084        }
085    
086    
087        public int available() throws IOException {
088            return (int)this.bytesRemaining;
089        }
090    
091    
092        public void close() throws IOException {
093            in.close();
094        }
095    
096    
097        public void mark(int readLimit) {
098            in.mark(readLimit);
099        }
100    
101    
102        public boolean markSupported() {
103            return in.markSupported();
104        }
105    
106    
107        public void reset() throws IOException  {
108            in.reset();
109        }
110    }