content: package acr.browser.thunder;
  
  import java.io.FilterInputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.util.Deque;
  import java.util.Iterator;
  import java.util.LinkedList;
  
  public class ReplacingInputStream extends FilterInputStream {
  
  	Deque<Integer> inQueue = new LinkedList<Integer>();
  
  	Deque<Integer> outQueue = new LinkedList<Integer>();
  
  	final byte[] search, replacement;
  
  	protected ReplacingInputStream(InputStream in, byte[] search, byte[] replacement) {
  		super(in);
  		this.search = search;
  		this.replacement = replacement;
  	}
  
  	private boolean isMatchFound() {
  		Iterator<Integer> inIter = inQueue.iterator();
  		for (int i = 0; i < search.length; i++) {
  			if (!inIter.hasNext() || search[i] != inIter.next()) {
  				return false;
  			}
  		}
  		return true;
  	}
  
  	private void readAhead() throws IOException {
  		// Work up some look-ahead.
  		while (inQueue.size() < search.length) {
  			int next = super.read();
  			inQueue.offer(next);
  			if (next == -1) {
  				break;
  			}
  		}
  	}
  
  	@Override
  	public int read() throws IOException {
  
  		// Next byte already determined.
  		if (outQueue.isEmpty()) {
  
  			readAhead();
  
  			if (isMatchFound()) {
  				for (int i = 0; i < search.length; i++) {
  					inQueue.remove();
  				}
  
  				for (byte b : replacement) {
  					outQueue.offer((int) b);
  				}
  			} else {
  				outQueue.add(inQueue.remove());
  			}
  		}
  
  		return outQueue.remove();
  	}
  
  	/**
  	 * Returns false. REFilterInputStream does not support mark() and reset()
  	 * methods.
  	 */
  	@Override
  	public boolean markSupported() {
  		return false;
  	}
  
  	/**
  	 * Reads from the stream into the provided array.
  	 */
  	@Override
  	public int read(byte[] b, int off, int len) throws IOException {
  		int i;
  		int ok = 0;
  		while (len-- > 0) {
  			i = read();
  			if (i == -1) {
  				return (ok == 0) ? -1 : ok;
  			}
  			b[off++] = (byte) i;
  			ok++;
  		}
  		return ok;
  	}
  
  	@Override
  	public int read(byte[] buffer) throws IOException {
  
  		return read(buffer, 0, buffer.length);
  	}
  }
  