1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 package org.spf4j.io;
33
34 import edu.umd.cs.findbugs.annotations.CleanupObligation;
35 import edu.umd.cs.findbugs.annotations.DischargesObligation;
36 import java.io.FilterReader;
37 import java.io.IOException;
38 import java.io.Reader;
39
40 @CleanupObligation
41 public final class PushbackReader extends FilterReader {
42
43 private char[] buf;
44
45 private int pos;
46
47 public PushbackReader(final Reader in, final int size) {
48 super(in);
49 if (size <= 0) {
50 throw new IllegalArgumentException("size " + size + " <= 0");
51 }
52 this.buf = new char[size];
53 this.pos = size;
54 }
55
56 public PushbackReader(final Reader in) {
57 this(in, 1);
58 }
59
60 private void ensureOpen() throws IOException {
61 if (buf == null) {
62 throw new IOException("Stream closed " + this);
63 }
64 }
65
66 @Override
67 public int read() throws IOException {
68 ensureOpen();
69 if (pos < buf.length) {
70 return buf[pos++];
71 } else {
72 return super.read();
73 }
74 }
75
76 @Override
77 public int read(final char[] cbuf, final int poff, final int plen) throws IOException {
78 int off = poff;
79 int len = plen;
80 ensureOpen();
81 if (len <= 0) {
82 if (len < 0) {
83 throw new IndexOutOfBoundsException("len = " + len);
84 } else if ((off < 0) || (off > cbuf.length)) {
85 throw new IndexOutOfBoundsException("off = " + off);
86 }
87 return 0;
88 }
89 int avail = buf.length - pos;
90 if (avail > 0) {
91 if (len < avail) {
92 avail = len;
93 }
94 System.arraycopy(buf, pos, cbuf, off, avail);
95 pos += avail;
96 off += avail;
97 len -= avail;
98 }
99 if (len > 0) {
100 len = super.read(cbuf, off, len);
101 if (len == -1) {
102 return (avail == 0) ? -1 : avail;
103 }
104 return avail + len;
105 }
106 return avail;
107 }
108
109 public void unread(final int c) throws IOException {
110 ensureOpen();
111 if (pos == 0) {
112 throw new IOException("Pushback buffer overflow " + this);
113 }
114 if (c >= 0) {
115 buf[--pos] = (char) c;
116 } else {
117 throw new IllegalArgumentException("pushing back invalid character " + c);
118 }
119 }
120
121 public void unread(final char[] cbuf, final int off, final int len) throws IOException {
122 ensureOpen();
123 if (len > pos) {
124 throw new IOException("Pushback buffer overflow " + this);
125 }
126 pos -= len;
127 System.arraycopy(cbuf, off, buf, pos, len);
128 }
129
130 public void unread(final char[] cbuf) throws IOException {
131 unread(cbuf, 0, cbuf.length);
132 }
133
134 @Override
135 public boolean ready() throws IOException {
136 ensureOpen();
137 return (pos < buf.length) || super.ready();
138 }
139
140 @Override
141 public void mark(final int readAheadLimit) throws IOException {
142 throw new IOException("mark/reset not supported " + this);
143 }
144
145 @Override
146 public void reset() throws IOException {
147 throw new IOException("mark/reset not supported " + this);
148 }
149
150 @Override
151 public boolean markSupported() {
152 return false;
153 }
154
155 @Override
156 @DischargesObligation
157 public void close() throws IOException {
158 super.close();
159 buf = null;
160 }
161
162 @Override
163 public long skip(final long pn) throws IOException {
164 long n = pn;
165 if (n < 0L) {
166 throw new IllegalArgumentException("skip value is negative " + pn);
167 }
168 ensureOpen();
169 int avail = buf.length - pos;
170 if (avail > 0) {
171 if (n <= avail) {
172 pos += n;
173 return n;
174 } else {
175 pos = buf.length;
176 n -= avail;
177 }
178 }
179 return avail + super.skip(n);
180 }
181
182 @Override
183 public String toString() {
184 return "PushbackReader{" + "buf=" + new String(buf)
185 + ", pos=" + pos + ", wrapped=" + super.in + '}';
186 }
187
188
189
190 }