View Javadoc

1   /*
2    * Copyright 2009 Red Hat, Inc.
3    *
4    * Red Hat licenses this file to you under the Apache License, version 2.0
5    * (the "License"); you may not use this file except in compliance with the
6    * License.  You may obtain a copy of the License at:
7    *
8    *    http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package org.jboss.netty.buffer;
17  
18  import java.io.DataInput;
19  import java.io.DataInputStream;
20  import java.io.EOFException;
21  import java.io.IOException;
22  import java.io.InputStream;
23  
24  /**
25   * An {@link InputStream} which reads data from a {@link ChannelBuffer}.
26   * <p>
27   * A read operation against this stream will occur at the {@code readerIndex}
28   * of its underlying buffer and the {@code readerIndex} will increase during
29   * the read operation.
30   * <p>
31   * This stream implements {@link DataInput} for your convenience.
32   * The endianness of the stream is not always big endian but depends on
33   * the endianness of the underlying buffer.
34   *
35   * @author <a href="http://www.jboss.org/netty/">The Netty Project</a>
36   * @author <a href="http://gleamynode.net/">Trustin Lee</a>
37   *
38   * @version $Rev: 2080 $, $Date: 2010-01-26 18:04:19 +0900 (Tue, 26 Jan 2010) $
39   *
40   * @see ChannelBufferOutputStream
41   * @apiviz.uses org.jboss.netty.buffer.ChannelBuffer
42   */
43  public class ChannelBufferInputStream extends InputStream implements DataInput {
44  
45      private final ChannelBuffer buffer;
46      private final int startIndex;
47      private final int endIndex;
48  
49      /**
50       * Creates a new stream which reads data from the specified {@code buffer}
51       * starting at the current {@code readerIndex} and ending at the current
52       * {@code writerIndex}.
53       */
54      public ChannelBufferInputStream(ChannelBuffer buffer) {
55          this(buffer, buffer.readableBytes());
56      }
57  
58      /**
59       * Creates a new stream which reads data from the specified {@code buffer}
60       * starting at the current {@code readerIndex} and ending at
61       * {@code readerIndex + length}.
62       *
63       * @throws IndexOutOfBoundsException
64       *         if {@code readerIndex + length} is greater than
65       *            {@code writerIndex}
66       */
67      public ChannelBufferInputStream(ChannelBuffer buffer, int length) {
68          if (buffer == null) {
69              throw new NullPointerException("buffer");
70          }
71          if (length < 0) {
72              throw new IllegalArgumentException("length: " + length);
73          }
74          if (length > buffer.readableBytes()) {
75              throw new IndexOutOfBoundsException();
76          }
77  
78          this.buffer = buffer;
79          startIndex = buffer.readerIndex();
80          endIndex = startIndex + length;
81          buffer.markReaderIndex();
82      }
83  
84      /**
85       * Returns the number of read bytes by this stream so far.
86       */
87      public int readBytes() {
88          return buffer.readerIndex() - startIndex;
89      }
90  
91      @Override
92      public int available() throws IOException {
93          return endIndex - buffer.readerIndex();
94      }
95  
96      @Override
97      public void mark(int readlimit) {
98          buffer.markReaderIndex();
99      }
100 
101     @Override
102     public boolean markSupported() {
103         return true;
104     }
105 
106     @Override
107     public int read() throws IOException {
108         if (!buffer.readable()) {
109             return -1;
110         }
111         return buffer.readByte() & 0xff;
112     }
113 
114     @Override
115     public int read(byte[] b, int off, int len) throws IOException {
116         int available = available();
117         if (available == 0) {
118             return -1;
119         }
120 
121         len = Math.min(available, len);
122         buffer.readBytes(b, off, len);
123         return len;
124     }
125 
126     @Override
127     public void reset() throws IOException {
128         buffer.resetReaderIndex();
129     }
130 
131     @Override
132     public long skip(long n) throws IOException {
133         if (n > Integer.MAX_VALUE) {
134             return skipBytes(Integer.MAX_VALUE);
135         } else {
136             return skipBytes((int) n);
137         }
138     }
139 
140     public boolean readBoolean() throws IOException {
141         checkAvailable(1);
142         return read() != 0;
143     }
144 
145     public byte readByte() throws IOException {
146         if (!buffer.readable()) {
147             throw new EOFException();
148         }
149         return buffer.readByte();
150     }
151 
152     public char readChar() throws IOException {
153         return (char) readShort();
154     }
155 
156     public double readDouble() throws IOException {
157         return Double.longBitsToDouble(readLong());
158     }
159 
160     public float readFloat() throws IOException {
161         return Float.intBitsToFloat(readInt());
162     }
163 
164     public void readFully(byte[] b) throws IOException {
165         readFully(b, 0, b.length);
166     }
167 
168     public void readFully(byte[] b, int off, int len) throws IOException {
169         checkAvailable(len);
170         buffer.readBytes(b, off, len);
171     }
172 
173     public int readInt() throws IOException {
174         checkAvailable(4);
175         return buffer.readInt();
176     }
177 
178     private final StringBuilder lineBuf = new StringBuilder();
179 
180     public String readLine() throws IOException {
181         lineBuf.setLength(0);
182         for (;;) {
183             int b = read();
184             if (b < 0 || b == '\n') {
185                 break;
186             }
187 
188             lineBuf.append((char) b);
189         }
190 
191         while (lineBuf.charAt(lineBuf.length() - 1) == '\r') {
192             lineBuf.setLength(lineBuf.length() - 1);
193         }
194 
195         return lineBuf.toString();
196     }
197 
198     public long readLong() throws IOException {
199         checkAvailable(8);
200         return buffer.readLong();
201     }
202 
203     public short readShort() throws IOException {
204         checkAvailable(2);
205         return buffer.readShort();
206     }
207 
208     public String readUTF() throws IOException {
209         return DataInputStream.readUTF(this);
210     }
211 
212     public int readUnsignedByte() throws IOException {
213         return readByte() & 0xff;
214     }
215 
216     public int readUnsignedShort() throws IOException {
217         return readShort() & 0xffff;
218     }
219 
220     public int skipBytes(int n) throws IOException {
221         int nBytes = Math.min(available(), n);
222         buffer.skipBytes(nBytes);
223         return nBytes;
224     }
225 
226     private void checkAvailable(int fieldSize) throws IOException {
227         if (fieldSize < 0) {
228             throw new IndexOutOfBoundsException();
229         }
230         if (fieldSize > available()) {
231             throw new EOFException();
232         }
233     }
234 }