1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  package io.netty.buffer;
17  
18  import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
19  
20  import io.netty.util.ReferenceCounted;
21  import io.netty.util.internal.ObjectUtil;
22  import io.netty.util.internal.StringUtil;
23  
24  import java.io.DataInput;
25  import java.io.DataInputStream;
26  import java.io.EOFException;
27  import java.io.IOException;
28  import java.io.InputStream;
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  public class ByteBufInputStream extends InputStream implements DataInput {
47      private final ByteBuf buffer;
48      private final int startIndex;
49      private final int endIndex;
50      private boolean closed;
51      
52  
53  
54  
55  
56  
57      private final boolean releaseOnClose;
58  
59      
60  
61  
62  
63  
64  
65      public ByteBufInputStream(ByteBuf buffer) {
66          this(buffer, buffer.readableBytes());
67      }
68  
69      
70  
71  
72  
73  
74  
75  
76  
77  
78  
79      public ByteBufInputStream(ByteBuf buffer, int length) {
80          this(buffer, length, false);
81      }
82  
83      
84  
85  
86  
87  
88  
89  
90  
91      public ByteBufInputStream(ByteBuf buffer, boolean releaseOnClose) {
92          this(buffer, buffer.readableBytes(), releaseOnClose);
93      }
94  
95      
96  
97  
98  
99  
100 
101 
102 
103 
104 
105 
106 
107     public ByteBufInputStream(ByteBuf buffer, int length, boolean releaseOnClose) {
108         ObjectUtil.checkNotNull(buffer, "buffer");
109         if (length < 0) {
110             if (releaseOnClose) {
111                 buffer.release();
112             }
113             checkPositiveOrZero(length, "length");
114         }
115         if (length > buffer.readableBytes()) {
116             if (releaseOnClose) {
117                 buffer.release();
118             }
119             throw new IndexOutOfBoundsException("Too many bytes to be read - Needs "
120                     + length + ", maximum is " + buffer.readableBytes());
121         }
122 
123         this.releaseOnClose = releaseOnClose;
124         this.buffer = buffer;
125         startIndex = buffer.readerIndex();
126         endIndex = startIndex + length;
127         buffer.markReaderIndex();
128     }
129 
130     
131 
132 
133     public int readBytes() {
134         return buffer.readerIndex() - startIndex;
135     }
136 
137     @Override
138     public void close() throws IOException {
139         try {
140             super.close();
141         } finally {
142             
143             if (releaseOnClose && !closed) {
144                 closed = true;
145                 buffer.release();
146             }
147         }
148     }
149 
150     @Override
151     public int available() throws IOException {
152         return endIndex - buffer.readerIndex();
153     }
154 
155     
156     @Override
157     public void mark(int readlimit) {
158         buffer.markReaderIndex();
159     }
160 
161     @Override
162     public boolean markSupported() {
163         return true;
164     }
165 
166     @Override
167     public int read() throws IOException {
168         int available = available();
169         if (available == 0) {
170             return -1;
171         }
172         return buffer.readByte() & 0xff;
173     }
174 
175     @Override
176     public int read(byte[] b, int off, int len) throws IOException {
177         int available = available();
178         if (available == 0) {
179             return -1;
180         }
181 
182         len = Math.min(available, len);
183         buffer.readBytes(b, off, len);
184         return len;
185     }
186 
187     
188     @Override
189     public void reset() throws IOException {
190         buffer.resetReaderIndex();
191     }
192 
193     @Override
194     public long skip(long n) throws IOException {
195         if (n > Integer.MAX_VALUE) {
196             return skipBytes(Integer.MAX_VALUE);
197         } else {
198             return skipBytes((int) n);
199         }
200     }
201 
202     @Override
203     public boolean readBoolean() throws IOException {
204         checkAvailable(1);
205         return read() != 0;
206     }
207 
208     @Override
209     public byte readByte() throws IOException {
210         checkAvailable(1);
211         return buffer.readByte();
212     }
213 
214     @Override
215     public char readChar() throws IOException {
216         return (char) readShort();
217     }
218 
219     @Override
220     public double readDouble() throws IOException {
221         return Double.longBitsToDouble(readLong());
222     }
223 
224     @Override
225     public float readFloat() throws IOException {
226         return Float.intBitsToFloat(readInt());
227     }
228 
229     @Override
230     public void readFully(byte[] b) throws IOException {
231         readFully(b, 0, b.length);
232     }
233 
234     @Override
235     public void readFully(byte[] b, int off, int len) throws IOException {
236         checkAvailable(len);
237         buffer.readBytes(b, off, len);
238     }
239 
240     @Override
241     public int readInt() throws IOException {
242         checkAvailable(4);
243         return buffer.readInt();
244     }
245 
246     private StringBuilder lineBuf;
247 
248     @Override
249     public String readLine() throws IOException {
250         int available = available();
251         if (available == 0) {
252             return null;
253         }
254 
255         if (lineBuf != null) {
256             lineBuf.setLength(0);
257         }
258 
259         loop: do {
260             int c = buffer.readUnsignedByte();
261             --available;
262             switch (c) {
263                 case '\n':
264                     break loop;
265 
266                 case '\r':
267                     if (available > 0 && (char) buffer.getUnsignedByte(buffer.readerIndex()) == '\n') {
268                         buffer.skipBytes(1);
269                         --available;
270                     }
271                     break loop;
272 
273                 default:
274                     if (lineBuf == null) {
275                         lineBuf = new StringBuilder();
276                     }
277                     lineBuf.append((char) c);
278             }
279         } while (available > 0);
280 
281         return lineBuf != null && lineBuf.length() > 0 ? lineBuf.toString() : StringUtil.EMPTY_STRING;
282     }
283 
284     @Override
285     public long readLong() throws IOException {
286         checkAvailable(8);
287         return buffer.readLong();
288     }
289 
290     @Override
291     public short readShort() throws IOException {
292         checkAvailable(2);
293         return buffer.readShort();
294     }
295 
296     @Override
297     public String readUTF() throws IOException {
298         return DataInputStream.readUTF(this);
299     }
300 
301     @Override
302     public int readUnsignedByte() throws IOException {
303         return readByte() & 0xff;
304     }
305 
306     @Override
307     public int readUnsignedShort() throws IOException {
308         return readShort() & 0xffff;
309     }
310 
311     @Override
312     public int skipBytes(int n) throws IOException {
313         int nBytes = Math.min(available(), n);
314         buffer.skipBytes(nBytes);
315         return nBytes;
316     }
317 
318     private void checkAvailable(int fieldSize) throws IOException {
319         if (fieldSize < 0) {
320             throw new IndexOutOfBoundsException("fieldSize cannot be a negative number");
321         }
322         if (fieldSize > available()) {
323             throw new EOFException("fieldSize is too long! Length is " + fieldSize
324                     + ", but maximum is " + available());
325         }
326     }
327 }