001 package edu.rice.cs.cunit.util;
002
003 import java.io.FilterInputStream;
004 import java.io.IOException;
005 import java.io.InputStream;
006
007 /** A stream that makes the position in the stream available. */
008 public class PositionInputStream extends FilterInputStream implements ProvidesInputStreamPosition {
009 /** Position. */
010 private long pos = 0;
011 /** Mark. */
012 private long mark = 0;
013
014 /** Create a new PositionInputStream based on the stream given.
015 * @param in input stream */
016 public PositionInputStream(InputStream in) {
017 super(in);
018 }
019
020 /**
021 * <p>Get the stream position.</p>
022 *
023 * <p>Eventually, the position will roll over to a negative number.
024 * Reading 1 Tb per second, this would occur after approximately three
025 * months. Applications should account for this possibility in their
026 * design.</p>
027 *
028 * @return the current stream position.
029 */
030 public synchronized long getPosition() {
031 return pos;
032 }
033
034 @Override
035 public synchronized int read() throws IOException {
036 int b = super.read();
037 if (b >= 0)
038 pos += 1;
039 return b;
040 }
041
042 @Override
043 public synchronized int read(byte[] b, int off, int len) throws IOException {
044 int n = super.read(b, off, len);
045 if (n > 0)
046 pos += n;
047 return n;
048 }
049
050 @Override
051 public synchronized long skip(long skip) throws IOException {
052 long n = super.skip(skip);
053 if (n > 0)
054 pos += n;
055 return n;
056 }
057
058 @Override
059 public synchronized void mark(int readlimit) {
060 super.mark(readlimit);
061 mark = pos;
062 }
063
064 @Override
065 public synchronized void reset() throws IOException {
066 /* A call to reset can still succeed if mark is not supported, but the
067 * resulting stream position is undefined, so it's not allowed here. */
068 if (!markSupported())
069 throw new IOException("Mark not supported.");
070 super.reset();
071 pos = mark;
072 }
073 }