package lejos.io;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import lejos.charset.CharsetDecoder;
public class LejosInputStreamReader extends Reader
{
private static final int MIN_BUFFERSIZE = 16;
private final CharsetDecoder coder;
private final InputStream is;
private final byte[] buffer;
private int offset;
private int limit;
//cache for storing a low surrogate
private char low;
public LejosInputStreamReader(InputStream is, CharsetDecoder coder, int buffersize)
{
this.is = is;
this.coder = coder;
if (buffersize < MIN_BUFFERSIZE)
buffersize = MIN_BUFFERSIZE;
if (coder.getMaxCharLength() > buffersize)
throw new IllegalArgumentException("buffer to small for given charset");
this.buffer = new byte[buffersize];
}
public int fillBuffer() throws IOException
{
int req = coder.estimateByteCount(buffer, offset, limit);
int len = limit - offset;
if (len < req)
{
int rem = buffer.length - offset;
if (rem < coder.getMaxCharLength())
{
System.arraycopy(buffer, offset, buffer, 0, len);
offset = 0;
limit = len;
}
do
{
int tmp = is.read(buffer, limit, buffer.length - limit);
if (tmp < 0)
//len is still smaller then req
return len;
len += tmp;
limit += tmp;
//update req, since initial value might have been an approximation
req = coder.estimateByteCount(buffer, offset, limit);
} while (len < req);
}
return req;
}
@Override
public int read() throws IOException
{
if (low > 0)
{
char tmp = this.low;
this.low = 0;
return tmp;
}
int needed = this.fillBuffer();
if (needed <= 0)
return -1;
int cp = this.coder.decode(buffer, offset, limit);
this.offset += needed;
if (cp < Character.MIN_SUPPLEMENTARY_CODE_POINT)
return cp;
cp -= Character.MIN_SUPPLEMENTARY_CODE_POINT;
this.low = (char)(cp & 0x3FF | Character.MIN_LOW_SURROGATE);
return (cp >> 10) | Character.MIN_HIGH_SURROGATE;
}
@Override
public int read(char[] cbuf, int off, int len) throws IOException
{
if (len < 1)
return 0;
int origoff = off;
// there should always be room for two chars, so substract 1
int endoff = off + len - 1;
int needed;
if (this.low > 0)
{
cbuf[off++] = this.low;
this.low = 0;
//don't fill buffer to avoid blocking
needed = this.coder.estimateByteCount(buffer, offset, limit);
}
else
{
//fill buffer
needed = this.fillBuffer();
}
if (off < endoff)
{
while (limit - offset >= needed)
{
int cp = this.coder.decode(buffer, offset, limit);
if (cp < Character.MIN_SUPPLEMENTARY_CODE_POINT)
{
cbuf[off++] = (char)cp;
}
else
{
cbuf[off++] = (char)((cp >> 10) + Character.MIN_HIGH_SURROGATE);
cbuf[off++] = (char)((cp & 0x3F) + Character.MIN_LOW_SURROGATE);
}
this.offset += needed;
if (off >= endoff)
break;
needed = this.coder.estimateByteCount(buffer, offset, limit);
}
}
return off - origoff;
}
@Override
public void close() throws IOException
{
// TODO Auto-generated method stub
}
}