package nl.helixsoft.util;
import java.io.IOException;
import java.io.InputStream;
/**
* A ring {@link InputStream} buffer with a peek() method to see ahead one character.
* <p>
* This is a fully functional InputStream, but the peek() method doesn't work with encodings, it just returns 1 byte
* This makes this class rather less useful for dealing with text - use {@link PeekReader} instead.
* */
public class ParseBuffer extends InputStream
{
static final int BUFFER_SIZE = 0x10000;
private final InputStream parent;
private final byte[] buf;
final int size;
int pos = 0;
int fill = 0;
boolean eof = false;
String charset = null;
public ParseBuffer (InputStream parent)
{
this (parent, BUFFER_SIZE, "UTF-8");
}
public ParseBuffer (InputStream parent, String charsetName)
{
this (parent, BUFFER_SIZE, charsetName);
}
public ParseBuffer (InputStream parent, int size)
{
this (parent, size, "UTF-8");
}
public ParseBuffer(InputStream parent, int size, String charsetName)
{
this.parent = parent;
buf = new byte[size];
this.size = size;
this.charset = charsetName;
}
@Override
public int read() throws IOException
{
int result = peek();
if (result < 0) return result;
pos++;
pos %= size;
return result;
}
/**
* @return the next byte as a positive value (between 0 and 255) or -1 on end-of-stream
*/
public int peek() throws IOException
{
if (pos == fill)
{
if (eof) return -1;
fillNext();
if (pos == fill && eof) return -1;
}
int result = buf[pos];
// make sure that bytes stay above 0
if (result < 0) result += 256;
return result;
}
private void fillNext() throws IOException
{
int end = Math.min (size, pos + (size / 2));
int delta = end - pos;
int result = parent.read(buf, fill, delta);
if (result < 0)
{
eof = true;
return;
}
fill += result;
fill %= size;
}
public int getPos()
{
return pos;
}
public String subString(int start, int end)
{
String result;
if (start < end)
result = new String(buf, start, end - start);
else
{
StringBuilder builder = new StringBuilder(size + end - start);
builder.append (new String(buf, start, (size - start)));
builder.append (new String(buf, 0, end));
result = builder.toString();
}
return result;
}
// for testing
int getFill()
{
return fill;
}
}