package org.araqne.log.api;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ByteChannel;
public class ByteBufferReader implements Closeable {
private ByteChannel channel;
public ByteBufferReader(ByteChannel channel) {
this.channel = channel;
buf = ByteBuffer.allocate(32768);
buf.position(buf.limit());
}
boolean skipLF;
int nextChar;
private ByteBuffer buf = ByteBuffer.allocate(32768);
private Object closeLock = new Object();
public ByteBuffer readLine() throws IOException {
return readLine(true);
}
public ByteBuffer readLine(boolean ignoreLF) throws IOException {
ensureOpen();
boolean omitLF = ignoreLF || skipLF;
ByteArrayOutputStream b = null;
for (;;) { // bufferloop
if (!buf.hasRemaining())// if (nextChar >= nChars)
fill();
if (!buf.hasRemaining()) { /* EOF */
if (b != null && b.size() > 0)
return ByteBuffer.wrap(b.toByteArray()).asReadOnlyBuffer();
else
return null;
}
boolean eol = false;
byte c = 0;
/* Skip a leftover '\n', if necessary */
if (omitLF && (buf.get(buf.position()) == '\n'))
buf.get();
skipLF = false;
omitLF = false;
// charloop
int oldPos = buf.position();
while (buf.hasRemaining()) {
c = buf.get();
if ((c == '\n') || (c == '\r')) {
eol = true;
break;
}
}
if (eol) {
ByteBuffer ret = null;
if (b == null) {
ret = buf.duplicate();
ret.limit(buf.position() - 1);
ret.position(oldPos);
ret = ret.asReadOnlyBuffer();
} else {
b.write(buf.array(), oldPos, buf.position() - 1 - oldPos);
ret = ByteBuffer.wrap(b.toByteArray()).asReadOnlyBuffer();
}
// nextChar++;
if (c == '\r') {
skipLF = true;
}
return ret;
}
if (b == null)
b = new ByteArrayOutputStream(1024);
b.write(buf.array(), oldPos, buf.position() - oldPos);
}
}
private void fill() throws IOException {
// buf has no remaining
buf.limit(buf.capacity());
buf.position(0);
int read = channel.read(buf);
buf.flip();
}
private void ensureOpen() throws IOException {
synchronized (closeLock) {
if (channel == null)
throw new IOException("Stream closed");
}
}
@Override
public void close() throws IOException {
synchronized (closeLock) {
channel.close();
channel = null;
}
}
}