package jdk.internal.org.jline.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.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CodingErrorAction;
public class NonBlocking {
public static NonBlockingPumpReader nonBlockingPumpReader() {
return new NonBlockingPumpReader();
}
public static NonBlockingPumpReader nonBlockingPumpReader(int size) {
return new NonBlockingPumpReader(size);
}
public static NonBlockingPumpInputStream nonBlockingPumpInputStream() {
return new NonBlockingPumpInputStream();
}
public static NonBlockingPumpInputStream nonBlockingPumpInputStream(int size) {
return new NonBlockingPumpInputStream(size);
}
public static NonBlockingInputStream nonBlockingStream(NonBlockingReader reader, Charset encoding) {
return new NonBlockingReaderInputStream(reader, encoding);
}
public static NonBlockingInputStream nonBlocking(String name, InputStream inputStream) {
if (inputStream instanceof NonBlockingInputStream) {
return (NonBlockingInputStream) inputStream;
}
return new NonBlockingInputStreamImpl(name, inputStream);
}
public static NonBlockingReader nonBlocking(String name, Reader reader) {
if (reader instanceof NonBlockingReader) {
return (NonBlockingReader) reader;
}
return new NonBlockingReaderImpl(name, reader);
}
public static NonBlockingReader nonBlocking(String name, InputStream inputStream, Charset encoding) {
return new NonBlockingInputStreamReader(nonBlocking(name, inputStream), encoding);
}
private static class NonBlockingReaderInputStream extends NonBlockingInputStream {
private final NonBlockingReader reader;
private final CharsetEncoder encoder;
private final ByteBuffer bytes;
private final CharBuffer chars;
private NonBlockingReaderInputStream(NonBlockingReader reader, Charset charset) {
this.reader = reader;
this.encoder = charset.newEncoder()
.onUnmappableCharacter(CodingErrorAction.REPLACE)
.onMalformedInput(CodingErrorAction.REPLACE);
this.bytes = ByteBuffer.allocate(4);
this.chars = CharBuffer.allocate(2);
this.bytes.limit(0);
this.chars.limit(0);
}
@Override
public int available() {
return (int) (reader.available() * this.encoder.averageBytesPerChar())
+ bytes.remaining();
}
@Override
public void close() throws IOException {
reader.close();
}
@Override
public int read(long timeout, boolean isPeek) throws IOException {
boolean isInfinite = (timeout <= 0L);
while (!bytes.hasRemaining() && (isInfinite || timeout > 0L)) {
long start = 0;
if (!isInfinite) {
start = System.currentTimeMillis();
}
int c = reader.read(timeout);
if (c == EOF) {
return EOF;
}
if (c >= 0) {
if (!chars.hasRemaining()) {
chars.position(0);
chars.limit(0);
}
int l = chars.limit();
chars.array()[chars.arrayOffset() + l] = (char) c;
chars.limit(l + 1);
bytes.clear();
encoder.encode(chars, bytes, false);
bytes.flip();
}
if (!isInfinite) {
timeout -= System.currentTimeMillis() - start;
}
}
if (bytes.hasRemaining()) {
if (isPeek) {
return Byte.toUnsignedInt(bytes.get(bytes.position()));
} else {
return Byte.toUnsignedInt(bytes.get());
}
} else {
return READ_EXPIRED;
}
}
}
private static class NonBlockingInputStreamReader extends NonBlockingReader {
private final NonBlockingInputStream input;
private final CharsetDecoder decoder;
private final ByteBuffer bytes;
private final CharBuffer chars;
public NonBlockingInputStreamReader(NonBlockingInputStream inputStream, Charset encoding) {
this(inputStream,
(encoding != null ? encoding : Charset.defaultCharset()).newDecoder()
.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE));
}
public NonBlockingInputStreamReader(NonBlockingInputStream input, CharsetDecoder decoder) {
this.input = input;
this.decoder = decoder;
this.bytes = ByteBuffer.allocate(4);
this.chars = CharBuffer.allocate(2);
this.bytes.limit(0);
this.chars.limit(0);
}
@Override
protected int read(long timeout, boolean isPeek) throws IOException {
boolean isInfinite = (timeout <= 0L);
while (!chars.hasRemaining() && (isInfinite || timeout > 0L)) {
long start = 0;
if (!isInfinite) {
start = System.currentTimeMillis();
}
int b = input.read(timeout);
if (b == EOF) {
return EOF;
}
if (b >= 0) {
if (!bytes.hasRemaining()) {
bytes.position(0);
bytes.limit(0);
}
int l = bytes.limit();
bytes.array()[bytes.arrayOffset() + l] = (byte) b;
bytes.limit(l + 1);
chars.clear();
decoder.decode(bytes, chars, false);
chars.flip();
}
if (!isInfinite) {
timeout -= System.currentTimeMillis() - start;
}
}
if (chars.hasRemaining()) {
if (isPeek) {
return chars.get(chars.position());
} else {
return chars.get();
}
} else {
return READ_EXPIRED;
}
}
@Override
public void shutdown() {
input.shutdown();
}
@Override
public void close() throws IOException {
input.close();
}
}
}