View Javadoc

    1   /*
    2    * Copyright 2012 The Netty Project
    3    *
    4    * The Netty Project licenses this file to you under the Apache License,
    5    * version 2.0 (the "License"); you may not use this file except in compliance
    6    * with the 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   * @see ChannelBufferOutputStream
    36   * @apiviz.uses org.jboss.netty.buffer.ChannelBuffer
    37   */
    38  public class ChannelBufferInputStream extends InputStream implements DataInput {
    39
    40      private final ChannelBuffer buffer;
    41      private final int startIndex;
    42      private final int endIndex;
    43
    44      /**
    45       * Creates a new stream which reads data from the specified {@code buffer}
    46       * starting at the current {@code readerIndex} and ending at the current
    47       * {@code writerIndex}.
    48       */
    49      public ChannelBufferInputStream(ChannelBuffer buffer) {
    50          this(buffer, buffer.readableBytes());
    51      }
    52
    53      /**
    54       * Creates a new stream which reads data from the specified {@code buffer}
    55       * starting at the current {@code readerIndex} and ending at
    56       * {@code readerIndex + length}.
    57       *
    58       * @throws IndexOutOfBoundsException
    59       *         if {@code readerIndex + length} is greater than
    60       *            {@code writerIndex}
    61       */
    62      public ChannelBufferInputStream(ChannelBuffer buffer, int length) {
    63          if (buffer == null) {
    64              throw new NullPointerException("buffer");
    65          }
    66          if (length < 0) {
    67              throw new IllegalArgumentException("length: " + length);
    68          }
    69          if (length > buffer.readableBytes()) {
    70              throw new IndexOutOfBoundsException("Too many bytes to be read - Needs "
    71                      + length + ", maximum is " + buffer.readableBytes());
    72          }
    73
    74          this.buffer = buffer;
    75          startIndex = buffer.readerIndex();
    76          endIndex = startIndex + length;
    77          buffer.markReaderIndex();
    78      }
    79
    80      /**
    81       * Returns the number of read bytes by this stream so far.
    82       */
    83      public int readBytes() {
    84          return buffer.readerIndex() - startIndex;
    85      }
    86
    87      @Override
    88      public int available() throws IOException {
    89          return endIndex - buffer.readerIndex();
    90      }
    91
    92      @Override
    93      public void mark(int readlimit) {
    94          buffer.markReaderIndex();
    95      }
    96
    97      @Override
    98      public boolean markSupported() {
    99          return true;
    100     }
    101
    102     @Override
    103     public int read() throws IOException {
    104         if (!buffer.readable()) {
    105             return -1;
    106         }
    107         return buffer.readByte() & 0xff;
    108     }
    109
    110     @Override
    111     public int read(byte[] b, int off, int len) throws IOException {
    112         int available = available();
    113         if (available == 0) {
    114             return -1;
    115         }
    116
    117         len = Math.min(available, len);
    118         buffer.readBytes(b, off, len);
    119         return len;
    120     }
    121
    122     @Override
    123     public void reset() throws IOException {
    124         buffer.resetReaderIndex();
    125     }
    126
    127     @Override
    128     public long skip(long n) throws IOException {
    129         if (n > Integer.MAX_VALUE) {
    130             return skipBytes(Integer.MAX_VALUE);
    131         } else {
    132             return skipBytes((int) n);
    133         }
    134     }
    135
    136     public boolean readBoolean() throws IOException {
    137         checkAvailable(1);
    138         return read() != 0;
    139     }
    140
    141     public byte readByte() throws IOException {
    142         if (!buffer.readable()) {
    143             throw new EOFException();
    144         }
    145         return buffer.readByte();
    146     }
    147
    148     public char readChar() throws IOException {
    149         return (char) readShort();
    150     }
    151
    152     public double readDouble() throws IOException {
    153         return Double.longBitsToDouble(readLong());
    154     }
    155
    156     public float readFloat() throws IOException {
    157         return Float.intBitsToFloat(readInt());
    158     }
    159
    160     public void readFully(byte[] b) throws IOException {
    161         readFully(b, 0, b.length);
    162     }
    163
    164     public void readFully(byte[] b, int off, int len) throws IOException {
    165         checkAvailable(len);
    166         buffer.readBytes(b, off, len);
    167     }
    168
    169     public int readInt() throws IOException {
    170         checkAvailable(4);
    171         return buffer.readInt();
    172     }
    173
    174     private final StringBuilder lineBuf = new StringBuilder();
    175
    176     public String readLine() throws IOException {
    177         lineBuf.setLength(0);
    178         for (;;) {
    179             int b = read();
    180             if (b < 0 || b == '\n') {
    181                 break;
    182             }
    183
    184             lineBuf.append((char) b);
    185         }
    186
    187         if (lineBuf.length() > 0) {
    188             while (lineBuf.charAt(lineBuf.length() - 1) == '\r') {
    189                 lineBuf.setLength(lineBuf.length() - 1);
    190             }
    191         }
    192
    193
    194         return lineBuf.toString();
    195     }
    196
    197     public long readLong() throws IOException {
    198         checkAvailable(8);
    199         return buffer.readLong();
    200     }
    201
    202     public short readShort() throws IOException {
    203         checkAvailable(2);
    204         return buffer.readShort();
    205     }
    206
    207     public String readUTF() throws IOException {
    208         return DataInputStream.readUTF(this);
    209     }
    210
    211     public int readUnsignedByte() throws IOException {
    212         return readByte() & 0xff;
    213     }
    214
    215     public int readUnsignedShort() throws IOException {
    216         return readShort() & 0xffff;
    217     }
    218
    219     public int skipBytes(int n) throws IOException {
    220         int nBytes = Math.min(available(), n);
    221         buffer.skipBytes(nBytes);
    222         return nBytes;
    223     }
    224
    225     private void checkAvailable(int fieldSize) throws IOException {
    226         if (fieldSize < 0) {
    227             throw new IndexOutOfBoundsException("fieldSize cannot be a negative number");
    228         }
    229         if (fieldSize > available()) {
    230             throw new EOFException("fieldSize is too long! Length is " + fieldSize
    231                     + ", but maximum is " + available());
    232         }
    233     }
    234 }