package org.bouncycastle.mail.smime.util; import javax.mail.internet.SharedInputStream; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Iterator; import java.util.LinkedList; import java.util.List; public class SharedFileInputStream extends FilterInputStream implements SharedInputStream { private final SharedFileInputStream _parent; private final File _file; private final long _start; private final long _length; private long _position; private long _markedPosition; private List _subStreams = new LinkedList(); public SharedFileInputStream( String fileName) throws IOException { this(new File(fileName)); } public SharedFileInputStream( File file) throws IOException { this(file, 0, file.length()); } private SharedFileInputStream( File file, long start, long length) throws IOException { super(new BufferedInputStream(new FileInputStream(file))); _parent = null; _file = file; _start = start; _length = length; in.skip(start); } private SharedFileInputStream( SharedFileInputStream parent, long start, long length) throws IOException { super(new BufferedInputStream(new FileInputStream(parent._file))); _parent = parent; _file = parent._file; _start = start; _length = length; in.skip(start); } public long getPosition() { return _position; } public InputStream newStream(long start, long finish) { try { SharedFileInputStream stream; if (finish < 0) { if (_length > 0) { stream = new SharedFileInputStream(this, _start + start, _length - start); } else if (_length == 0) { stream = new SharedFileInputStream(this, _start + start, 0); } else { stream = new SharedFileInputStream(this, _start + start, -1); } } else { stream = new SharedFileInputStream(this, _start + start, finish - start); } _subStreams.add(stream); return stream; } catch (IOException e) { throw new IllegalStateException("unable to create shared stream: " + e); } } public int read( byte[] buf) throws IOException { return this.read(buf, 0, buf.length); } public int read( byte[] buf, int off, int len) throws IOException { int count = 0; if (len == 0) { return 0; } while (count < len) { int ch = this.read(); if (ch < 0) { break; } buf[off + count] = (byte)ch; count++; } if (count == 0) { return -1; // EOF } return count; } public int read() throws IOException { if (_position == _length) { return -1; } _position++; return in.read(); } public boolean markSupported() { return true; } public long skip(long n) throws IOException { long count; for (count = 0; count != n; count++) { if (this.read() < 0) { break; } } return count; } public void mark( int readLimit) { _markedPosition = _position; in.mark(readLimit); } public void reset() throws IOException { _position = _markedPosition; in.reset(); } /** * Return the shared stream that represents the top most stream that * this stream inherits from. * @return the base of the shared stream tree. */ public SharedFileInputStream getRoot() { if (_parent != null) { return _parent.getRoot(); } return this; } /** * Close of this stream and any substreams that have been created from it. * @throws IOException on problem closing the main stream. */ public void dispose() throws IOException { Iterator it = _subStreams.iterator(); while (it.hasNext()) { try { ((SharedFileInputStream)it.next()).dispose(); } catch (IOException e) { // ignore } } in.close(); } }