001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.io;
019
020import java.io.InputStream;
021import java.nio.ByteBuffer;
022
023import org.apache.hadoop.hbase.util.ByteBufferUtils;
024import org.apache.yetus.audience.InterfaceAudience;
025
026/**
027 * Not thread safe!
028 * <p>
029 * Please note that the reads will cause position movement on wrapped ByteBuffer.
030 */
031@InterfaceAudience.Private
032public class ByteBufferInputStream extends InputStream {
033
034  private ByteBuffer buf;
035
036  public ByteBufferInputStream(ByteBuffer buf) {
037    this.buf = buf;
038  }
039
040  /**
041   * Reads the next byte of data from this input stream. The value byte is returned as an
042   * <code>int</code> in the range <code>0</code> to <code>255</code>. If no byte is available
043   * because the end of the stream has been reached, the value <code>-1</code> is returned.
044   * @return the next byte of data, or <code>-1</code> if the end of the stream has been reached.
045   */
046  @Override
047  public int read() {
048    if (this.buf.hasRemaining()) {
049      return (this.buf.get() & 0xff);
050    }
051    return -1;
052  }
053
054  /**
055   * Reads up to next <code>len</code> bytes of data from buffer into passed array(starting from
056   * given offset).
057   * @param b the array into which the data is read.
058   * @param off the start offset in the destination array <code>b</code>
059   * @param len the maximum number of bytes to read.
060   * @return the total number of bytes actually read into the buffer, or <code>-1</code> if not even
061   *         1 byte can be read because the end of the stream has been reached.
062   */
063  @Override
064  public int read(byte[] b, int off, int len) {
065    int avail = available();
066    if (avail <= 0) {
067      return -1;
068    }
069
070    if (len > avail) {
071      len = avail;
072    }
073    if (len <= 0) {
074      return 0;
075    }
076
077    ByteBufferUtils.copyFromBufferToArray(b, this.buf, this.buf.position(), off, len);
078    this.buf.position(this.buf.position() + len); // we should advance the buffer position
079    return len;
080  }
081
082  /**
083   * Skips <code>n</code> bytes of input from this input stream. Fewer bytes might be skipped if the
084   * end of the input stream is reached. The actual number <code>k</code> of bytes to be skipped is
085   * equal to the smaller of <code>n</code> and remaining bytes in the stream.
086   * @param n the number of bytes to be skipped.
087   * @return the actual number of bytes skipped.
088   */
089  @Override
090  public long skip(long n) {
091    long k = Math.min(n, available());
092    if (k < 0) {
093      k = 0;
094    }
095    this.buf.position((int) (this.buf.position() + k));
096    return k;
097  }
098
099  /**
100   * @return  the number of remaining bytes that can be read (or skipped
101   *          over) from this input stream.
102   */
103  @Override
104  public int available() {
105    return this.buf.remaining();
106  }
107}