All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.abdera.i18n.text.io.RewindableInputStream Maven / Gradle / Ivy

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  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.  For additional information regarding
* copyright in this work, please see the NOTICE file in the top level
* directory of this distribution.
*/
package org.apache.abdera.i18n.text.io;

import java.io.IOException;
import java.io.InputStream;

/**
 * RewindableInputStream is a specialization of the PushbackInputStream
 * that maintains an internal buffer of read bytes that a user can 
 * rewind (unread) back into the stream without having to do their 
 * own buffer management.  The rewind buffer grows dynamically
 */
public class RewindableInputStream 
  extends DynamicPushbackInputStream {

  private static final int INITIAL_CAPACITY = 32;
  private byte[] buffer;
  private int position;
  private final int scale;
  
  public RewindableInputStream(
    InputStream in) {
      this(in,INITIAL_CAPACITY);
  }
  
  public RewindableInputStream(
    InputStream in, 
    int capacity) {
      super(in);
      grow(capacity);
      this.scale = capacity;
  }

  public int position() {
    return position;
  }
  
  private void grow(int capacity)  {
    if (buffer == null) {
      buffer = new byte[capacity];
      return;
    } else {
      byte[] buf =  new byte[buffer.length + capacity];
      System.arraycopy(buffer, 0, buf, 0, buffer.length);
      buffer = buf;
    }
  }
  
  private void shrink(int len) {
    if (buffer == null) return;
    byte[] buf = new byte[buffer.length-len];
    System.arraycopy(buffer, 0, buf, 0, buf.length);
    position = buffer.length-len;
    buffer = buf;
  }
  
  public void rewind() throws IOException {
    if (buffer.length == 0) return;
    unread(buffer,0,position);
    shrink(buffer.length);
  }
  
  public void rewind(int offset, int len) throws IOException {
    if (buffer.length == 0) return;
    if (offset > buffer.length) 
      throw new ArrayIndexOutOfBoundsException(offset);
    unread(buffer,offset,len);
    shrink(len);
  }
  
  public void rewind(int len) throws IOException {
    if (buffer.length == 0) return;
    rewind(buffer.length-len,len);
  }
  
  public int read() throws IOException {
    int i = super.read();
    if (i != -1) {
      if (position >= buffer.length) grow(scale);
      buffer[position++] = (byte) i;
    }
    return i;
  }

  public int read(byte[] b, int off, int len) throws IOException {
    int r = super.read(b, off, len);
    if (r != -1) {
      if (position + r >= buffer.length) grow(Math.max(position+r,scale));
      System.arraycopy(b, off, buffer, position, r);
      position = position + r;
    }
    return r;
  }

  public long skip(long n) throws IOException {
    return super.skip(n);
  }
  
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy