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.activemq.transport.tcp;
  
  import java.io.FilterInputStream;
  import java.io.IOException;
  import java.io.InputStream;
  
  /**
   * An optimized buffered input stream for Tcp
   *
   *
   */
  public class TcpBufferedInputStream extends FilterInputStream {
      private static final int DEFAULT_BUFFER_SIZE = 8192;
      protected byte internalBuffer[];
      protected int count;
      protected int position;
  
      public TcpBufferedInputStream(InputStream in) {
          this(in, DEFAULT_BUFFER_SIZE);
      }
  
      public TcpBufferedInputStream(InputStream in, int size) {
          super(in);
          if (size <= 0) {
              throw new IllegalArgumentException("Buffer size <= 0");
          }
          internalBuffer = new byte[size];
      }
  
      protected void fill() throws IOException {
          byte[] buffer = internalBuffer;
          count = 0;
          position = 0;
          int n = in.read(buffer, position, buffer.length - position);
          if (n > 0) {
              count = n + position;
          }
      }
  
      @Override
      public int read() throws IOException {
          if (position >= count) {
              fill();
              if (position >= count) {
                  return -1;
              }
          }
          return internalBuffer[position++] & 0xff;
      }
  
      private int readStream(byte[] b, int off, int len) throws IOException {
          int avail = count - position;
          if (avail <= 0) {
              if (len >= internalBuffer.length) {
                  return in.read(b, off, len);
              }
              fill();
              avail = count - position;
              if (avail <= 0) {
                  return -1;
              }
          }
          int cnt = (avail < len) ? avail : len;
          System.arraycopy(internalBuffer, position, b, off, cnt);
          position += cnt;
          return cnt;
      }
  
      @Override
      public int read(byte b[], int off, int len) throws IOException {
          if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
              throw new IndexOutOfBoundsException();
          } else if (len == 0) {
              return 0;
          }
          int n = 0;
          for (;;) {
              int nread = readStream(b, off + n, len - n);
              if (nread <= 0) {
                  return (n == 0) ? nread : n;
              }
              n += nread;
              if (n >= len) {
                  return n;
              }
              // if not closed but no bytes available, return
              InputStream input = in;
              if (input != null && input.available() <= 0) {
                  return n;
              }
          }
      }
  
      @Override
      public long skip(long n) throws IOException {
          if (n <= 0) {
              return 0;
          }
          long avail = count - position;
          if (avail <= 0) {
              return in.skip(n);
          }
          long skipped = (avail < n) ? avail : n;
          position += skipped;
          return skipped;
      }
  
      @Override
      public int available() throws IOException {
          return in.available() + (count - position);
      }
  
      @Override
      public boolean markSupported() {
          return false;
      }
  
      @Override
      public void close() throws IOException {
          if (in != null) {
              in.close();
          }
      }
  
      /**
       * @param array
       * @throws IOException
       */
      public void unread(byte[] array) throws IOException {
          int avail = internalBuffer.length - position;
          if (array.length > avail) {
              throw new IOException("Buffer is full, can't unread");
          }
  
          System.arraycopy(array, position, internalBuffer, 0, array.length);
          count += array.length;
      }
  }
  