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    }