Skip to content

Instantly share code, notes, and snippets.

@ncruces
Created July 2, 2021 17:51
Show Gist options
  • Save ncruces/e0e8d0b0e563ddca4783472d2493103f to your computer and use it in GitHub Desktop.
Save ncruces/e0e8d0b0e563ddca4783472d2493103f to your computer and use it in GitHub Desktop.
InputStream that reads from a Reader
package io.github.ncruces.utils;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import java.nio.charset.CodingErrorAction;
public final class ReaderInputStream extends InputStream {
private static final int DEFAULT_BUFFER_SIZE = 1024;
private final Reader reader;
private final CharsetEncoder encoder;
private final CharBuffer ibuf;
private final ByteBuffer obuf;
private boolean endOfInput;
private CoderResult lastResult;
public ReaderInputStream(Reader reader) {
this(reader, Charset.defaultCharset());
}
public ReaderInputStream(Reader reader, Charset charset) {
this(reader, charset.newEncoder().
onMalformedInput(CodingErrorAction.REPLACE).
onUnmappableCharacter(CodingErrorAction.REPLACE));
}
public ReaderInputStream(Reader reader, CharsetEncoder encoder) {
this.reader = reader;
this.encoder = encoder;
this.ibuf = CharBuffer.allocate(DEFAULT_BUFFER_SIZE);
this.ibuf.flip();
this.obuf = ByteBuffer.allocate(128);
this.obuf.flip();
}
public ReaderInputStream(Reader reader, String charsetName) {
this(reader, Charset.forName(charsetName));
}
@Override
public void close() throws IOException {
reader.close();
}
@Override
public int read() throws IOException {
while (true) {
if (obuf.hasRemaining()) return obuf.get() & 0xff;
if (!fillBuffer()) return -1;
}
}
@Override
public int read(byte[] b) throws IOException {
return read(0, b.length, b);
}
@Override
public synchronized int read(byte[] b, int off, int len) throws IOException {
if ((off | len | off + len | b.length - (off + len)) < 0) {
throw new IndexOutOfBoundsException();
}
return read(off, len, b);
}
private int read(int off, int len, byte[] b) throws IOException {
if (len == 0) return 0;
int res = 0;
while (len > 0) {
int rem = obuf.remaining();
if (rem > 0) {
if (rem > len) rem = len;
obuf.get(b, off, rem);
off += rem;
len -= rem;
res += rem;
} else {
if (!fillBuffer()) break;
}
}
return res > 0 || !endOfInput ? res : -1;
}
private boolean fillBuffer() throws IOException {
if (!endOfInput && (lastResult == null || lastResult.isUnderflow())) {
ibuf.compact();
int pos = ibuf.position();
int n = reader.read(ibuf.array(), pos, ibuf.remaining());
if (n < 0) {
endOfInput = true;
} else {
ibuf.position(pos + n);
}
ibuf.flip();
}
obuf.compact();
lastResult = encoder.encode(ibuf, obuf, endOfInput);
obuf.flip();
return !endOfInput || obuf.hasRemaining();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment