+
+ private static class RollbackReader extends Reader {
+ private final Reader r;
+ public RollbackReader(Reader r) { this.r = r; }
+
+ private char[] queue = new char[1024];
+ private int head = 0;
+ private int tail = 0;
+
+ private void unread(char c) {
+ if (tail >= queue.length) {
+ if (tail - head > queue.length/2) {
+ char[] queue2 = new char[queue.length * 2];
+ System.arraycopy(queue, head, queue2, 0, tail-head);
+ } else {
+ System.arraycopy(queue, head, queue, 0, tail-head);
+ }
+ tail = tail-head;
+ head = 0;
+ }
+ queue[tail++] = c;
+ }
+
+ public void close() throws IOException { r.close(); }
+ public int read() throws IOException {
+ if (tail>head)
+ return queue[head++];
+ return r.read();
+ }
+ public int read(char cbuf[]) throws IOException { return read(cbuf, 0, cbuf.length); }
+ public int read(char cbuf[], int off, int len) throws IOException {
+ if (tail>head) {
+ int count = Math.min(len, tail-head);
+ System.arraycopy(queue, head, cbuf, off, count);
+ head += count;
+ return count;
+ }
+ return r.read(cbuf, off, len);
+ }
+ public long skip(long n) throws IOException { return r.skip(n); }
+ public boolean ready() throws IOException { return true; }
+ public boolean markSupported() { return false; }
+ public void mark(int readAheadLimit) throws IOException { throw new IOException("not supported"); }
+ public void reset() throws IOException { throw new IOException("not supported"); }
+ }
+
+ private final RollbackReader r;