View Javadoc
1   /*
2    * Copyright (c) 2001-2017, Zoltan Farkas All Rights Reserved.
3    *
4    * This library is free software; you can redistribute it and/or
5    * modify it under the terms of the GNU Lesser General Public
6    * License as published by the Free Software Foundation; either
7    * version 2.1 of the License, or (at your option) any later version.
8    *
9    * This library is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   * GNU General Public License for more details.
13   *
14   * You should have received a copy of the GNU Lesser General Public
15   * License along with this program; if not, write to the Free Software
16   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17   *
18   * Additionally licensed with:
19   *
20   * Licensed under the Apache License, Version 2.0 (the "License");
21   * you may not use this file except in compliance with the License.
22   * You may obtain a copy of the License at
23   *
24   *      http://www.apache.org/licenses/LICENSE-2.0
25   *
26   * Unless required by applicable law or agreed to in writing, software
27   * distributed under the License is distributed on an "AS IS" BASIS,
28   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29   * See the License for the specific language governing permissions and
30   * limitations under the License.
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 }