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 }