content: /**
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to You under the Apache License, Version 2.0
   * (the "License"); you may not use this file except in compliance with
   * the License.  You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package org.apache.solr.common.util;
  
  import java.io.*;
  
  /** Single threaded buffered InputStream
   *  Internal Solr use only, subject to change.
   */
  public class FastInputStream extends InputStream implements DataInput {
    private final InputStream in;
    private final byte[] buf;
    private int pos;
    private int end;
  
    public FastInputStream(InputStream in) {
    // use default BUFSIZE of BufferedOutputStream so if we wrap that
    // it won't cause double buffering.
      this(in, new byte[8192], 0, 0);
    }
  
    public FastInputStream(InputStream in, byte[] tempBuffer, int start, int end) {
      this.in = in;
      this.buf = tempBuffer;
      this.pos = start;
      this.end = end;
    }
  
  
    public static FastInputStream wrap(InputStream in) {
      return (in instanceof FastInputStream) ? (FastInputStream)in : new FastInputStream(in);
    }
  
    @Override
    public int read() throws IOException {
      if (pos >= end) {
        refill();
        if (pos >= end) return -1;
      }
      return buf[pos++] & 0xff;     
    }
  
    public int readUnsignedByte() throws IOException {
      if (pos >= end) {
        refill();
        if (pos >= end) throw new EOFException();
      }
      return buf[pos++] & 0xff;
    }
  
    public void refill() throws IOException {
      // this will set end to -1 at EOF
      end = in.read(buf, 0, buf.length);
      pos = 0;
    }
  
    @Override
    public int available() throws IOException {
      return end - pos;
    }
  
    @Override
    public int read(byte b[], int off, int len) throws IOException {
      int r=0;  // number of bytes read
      // first read from our buffer;
      if (end-pos > 0) {
        r = Math.min(end-pos, len);
        System.arraycopy(buf, pos, b, off, r);      
        pos += r;
      }
  
      if (r == len) return r;
  
      // amount left to read is >= buffer size
      if (len-r >= buf.length) {
        int ret = in.read(b, off+r, len-r);
        if (ret==-1) return r==0 ? -1 : r;
        r += ret;
        return r;
      }
  
      refill();
  
      // first read from our buffer;
      if (end-pos > 0) {
        int toRead = Math.min(end-pos, len-r);
        System.arraycopy(buf, pos, b, off+r, toRead);
        pos += toRead;
        r += toRead;
        return r;
      }
      
      return r > 0 ? r : -1;
    }
  
    @Override
    public void close() throws IOException {
      in.close();
    }
  
    public void readFully(byte b[]) throws IOException {
      readFully(b, 0, b.length);
    }
  
    public void readFully(byte b[], int off, int len) throws IOException {
      while (len>0) {
        int ret = read(b, off, len);
        if (ret==-1) {
          throw new EOFException();
        }
        off += ret;
        len -= ret;
      }
    }
  
    public int skipBytes(int n) throws IOException {
      if (end-pos >= n) {
        pos += n;
        return n;
      }
  
      if (end-pos<0) return -1;
      
      int r = end-pos;
      pos = end;
  
      while (r < n) {
        refill();
        if (end-pos <= 0) return r;
        int toRead = Math.min(end-pos, n-r);
        r += toRead;
        pos += toRead;
      }
  
      return r;
    }
  
    public boolean readBoolean() throws IOException {
      return readByte()==1;
    }
  
    public byte readByte() throws IOException {
      if (pos >= end) {
        refill();
        if (pos >= end) throw new EOFException();
      }
      return buf[pos++];
    }
  
  
    public short readShort() throws IOException {
      return (short)((readUnsignedByte() << 8) | readUnsignedByte());
    }
  
    public int readUnsignedShort() throws IOException {
      return (readUnsignedByte() << 8) | readUnsignedByte();
    }
  
    public char readChar() throws IOException {
      return (char)((readUnsignedByte() << 8) | readUnsignedByte());
    }
  
    public int readInt() throws IOException {
      return  ((readUnsignedByte() << 24)
              |(readUnsignedByte() << 16)
              |(readUnsignedByte() << 8)
              | readUnsignedByte());
    }
  
    public long readLong() throws IOException {
      return  (((long)readUnsignedByte()) << 56)
              | (((long)readUnsignedByte()) << 48)
              | (((long)readUnsignedByte()) << 40)
              | (((long)readUnsignedByte()) << 32)
              | (((long)readUnsignedByte()) << 24)
              | (readUnsignedByte() << 16)
              | (readUnsignedByte() << 8)
              | (readUnsignedByte());
    }
  
    public float readFloat() throws IOException {
      return Float.intBitsToFloat(readInt());    
    }
  
    public double readDouble() throws IOException {
      return Double.longBitsToDouble(readLong());    
    }
  
    public String readLine() throws IOException {
      return new DataInputStream(this).readLine();
    }
  
    public String readUTF() throws IOException {
      return new DataInputStream(this).readUTF();
    }
  }
  