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;
022import org.apache.hadoop.hbase.util.ByteBufferUtils;
023import org.apache.yetus.audience.InterfaceAudience;
024
025/**
026 * Not thread safe!
027 * <p>
028 * Please note that the reads will cause position movement on wrapped ByteBuffer.
029 */
030@InterfaceAudience.Private
031public class ByteBufferInputStream extends InputStream {
032
033  private ByteBuffer buf;
034
035  public ByteBufferInputStream(ByteBuffer buf) {
036    this.buf = buf;
037  }
038
039  /**
040   * Reads the next byte of data from this input stream. The value byte is returned as an
041   * <code>int</code> in the range <code>0</code> to <code>255</code>. If no byte is available
042   * because the end of the stream has been reached, the value <code>-1</code> is returned.
043   * @return the next byte of data, or <code>-1</code> if the end of the stream has been reached.
044   */
045  @Override
046  public int read() {
047    if (this.buf.hasRemaining()) {
048      return (this.buf.get() & 0xff);
049    }
050    return -1;
051  }
052
053  /**
054   * Reads up to next <code>len</code> bytes of data from buffer into passed array(starting from
055   * given offset).
056   * @param b   the array into which the data is read.
057   * @param off the start offset in the destination array <code>b</code>
058   * @param len the maximum number of bytes to read.
059   * @return the total number of bytes actually read into the buffer, or <code>-1</code> if not even
060   *         1 byte can be read because the end of the stream has been reached.
061   */
062  @Override
063  public int read(byte[] b, int off, int len) {
064    int avail = available();
065    if (avail <= 0) {
066      return -1;
067    }
068
069    if (len > avail) {
070      len = avail;
071    }
072    if (len <= 0) {
073      return 0;
074    }
075
076    ByteBufferUtils.copyFromBufferToArray(b, this.buf, this.buf.position(), off, len);
077    this.buf.position(this.buf.position() + len); // we should advance the buffer position
078    return len;
079  }
080
081  /**
082   * Skips <code>n</code> bytes of input from this input stream. Fewer bytes might be skipped if the
083   * end of the input stream is reached. The actual number <code>k</code> of bytes to be skipped is
084   * equal to the smaller of <code>n</code> and remaining bytes in the stream.
085   * @param n the number of bytes to be skipped.
086   * @return the actual number of bytes skipped.
087   */
088  @Override
089  public long skip(long n) {
090    long k = Math.min(n, available());
091    if (k < 0) {
092      k = 0;
093    }
094    this.buf.position((int) (this.buf.position() + k));
095    return k;
096  }
097
098  /**
099   * @return the number of remaining bytes that can be read (or skipped over) from this input
100   *         stream.
101   */
102  @Override
103  public int available() {
104    return this.buf.remaining();
105  }
106}