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 }