Created
July 2, 2021 17:51
-
-
Save ncruces/e0e8d0b0e563ddca4783472d2493103f to your computer and use it in GitHub Desktop.
InputStream that reads from a Reader
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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