ByteReaderBack.java
package space.sunqian.fs.io;
import space.sunqian.annotation.Nonnull;
import space.sunqian.annotation.Nullable;
import space.sunqian.fs.Fs;
import space.sunqian.fs.base.bytes.BytesKit;
import space.sunqian.fs.base.math.MathKit;
import space.sunqian.fs.io.IOChecker.ReadChecker;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
final class ByteReaderBack {
static @Nonnull ByteReader of(@Nonnull InputStream src, int bufSize) throws IllegalArgumentException {
IOChecker.checkBufSize(bufSize);
return new ByteStreamReader(src, bufSize);
}
static @Nonnull ByteReader of(@Nonnull ReadableByteChannel src, int bufSize) throws IllegalArgumentException {
IOChecker.checkBufSize(bufSize);
return new ByteChannelReader(src, bufSize);
}
static @Nonnull ByteReader of(byte @Nonnull [] src, int off, int len) throws IndexOutOfBoundsException {
IOChecker.checkOffLen(off, len, src.length);
return new ByteArrayReader(src, off, len);
}
static @Nonnull ByteReader of(@Nonnull ByteBuffer src) {
return new ByteBufferReader(src);
}
static @Nonnull ByteReader limit(@Nonnull ByteReader reader, long limit) throws IllegalArgumentException {
IOChecker.checkLimit(limit);
return new LimitedReader(reader, limit);
}
static @Nonnull ByteSegment newSeg(@Nonnull ByteBuffer data, boolean end) {
return new ByteSegmentImpl(data, end);
}
static @Nonnull ByteSegment emptySeg(boolean end) {
return end ? ByteSegmentImpl.EMPTY_END : ByteSegmentImpl.EMPTY_SEG;
}
static @Nonnull InputStream asInputStream(@Nonnull ByteReader reader) {
return new AsInputStream(reader);
}
private static final class ByteSegmentImpl implements ByteSegment {
private static final @Nonnull ByteSegmentImpl EMPTY_END = new ByteSegmentImpl(BytesKit.emptyBuffer(), true);
private static final @Nonnull ByteSegmentImpl EMPTY_SEG = new ByteSegmentImpl(BytesKit.emptyBuffer(), false);
private final @Nonnull ByteBuffer data;
private final boolean end;
private ByteSegmentImpl(@Nonnull ByteBuffer data, boolean end) {
this.data = data;
this.end = end;
}
@Override
public @Nonnull ByteBuffer data() {
return data;
}
@Override
public boolean end() {
return end;
}
@SuppressWarnings("MethodDoesntCallSuperMethod")
@Override
public @Nonnull ByteSegment clone() {
ByteBuffer copy = ByteBuffer.allocate(data.remaining());
int pos = data.position();
int limit = data.limit();
copy.put(data);
data.position(pos);
data.limit(limit);
copy.flip();
return new ByteSegmentImpl(copy, end);
}
}
private static final class ByteStreamReader implements ByteReader {
private final @Nonnull InputStream src;
private final int bufSize;
private ByteStreamReader(@Nonnull InputStream src, int bufSize) {
this.src = src;
this.bufSize = bufSize;
}
@Override
public int ready() throws IORuntimeException {
try {
return src.available();
} catch (IOException e) {
throw new IORuntimeException(e);
}
}
@Override
public @Nonnull ByteSegment read(int len) throws IllegalArgumentException, IORuntimeException {
IOChecker.checkLen(len);
byte[] data = IOKit.read0(src, len, bufSize, IOChecker.endChecker());
if (data == null) {
return ByteSegment.empty(true);
}
return ByteSegment.of(ByteBuffer.wrap(data), data.length < len);
}
@Override
public @Nullable ByteBuffer read() throws IORuntimeException {
byte[] buf = IOKit.read0(src, bufSize, IOChecker.endChecker());
if (buf == null) {
return null;
}
return ByteBuffer.wrap(buf);
}
@Override
public long skip(long len) throws IllegalArgumentException, IORuntimeException {
IOChecker.checkSkip(len);
if (len == 0) {
return 0;
}
try {
return skip0(len);
} catch (Exception e) {
throw new IORuntimeException(e);
}
}
private long skip0(long len) throws IOException {
long hasRead = 0;
while (hasRead < len) {
long onceSize = src.skip(len - hasRead);
if (onceSize == 0) {
if (src.read() == -1) {
break;
} else {
hasRead++;
}
}
hasRead += onceSize;
}
return hasRead;
}
@Override
public long readTo(@Nonnull OutputStream dst) throws IORuntimeException {
return readTo(dst, IOChecker.endChecker());
}
@Override
public long readTo(@Nonnull OutputStream dst, long len) throws IllegalArgumentException, IORuntimeException {
return readTo(dst, len, IOChecker.endChecker());
}
@Override
public long readTo(@Nonnull WritableByteChannel dst) throws IORuntimeException {
return readTo(dst, IOChecker.endChecker());
}
@Override
public long readTo(
@Nonnull WritableByteChannel dst, long len
) throws IllegalArgumentException, IORuntimeException {
return readTo(dst, len, IOChecker.endChecker());
}
@Override
public int readTo(byte @Nonnull [] dst) throws IORuntimeException {
return readTo(dst, IOChecker.endChecker());
}
@Override
public int readTo(byte @Nonnull [] dst, int off, int len) throws IndexOutOfBoundsException, IORuntimeException {
return readTo(dst, off, len, IOChecker.endChecker());
}
@Override
public int readTo(@Nonnull ByteBuffer dst) throws IORuntimeException {
return readTo(dst, IOChecker.endChecker());
}
@Override
public int readTo(@Nonnull ByteBuffer dst, int len) throws IllegalArgumentException, IORuntimeException {
return readTo(dst, len, IOChecker.endChecker());
}
@Override
public @Nonnull ByteSegment available(int len) throws IllegalArgumentException, IORuntimeException {
IOChecker.checkLen(len);
byte[] data = IOKit.read0(src, len, bufSize, IOChecker.availableChecker());
if (data == null) {
return ByteSegment.empty(true);
}
return ByteSegment.of(ByteBuffer.wrap(data), false);
}
@Override
public @Nonnull ByteSegment available() throws IORuntimeException {
byte[] data = IOKit.read0(src, bufSize, IOChecker.availableChecker());
if (data == null) {
return ByteSegment.empty(true);
}
return ByteSegment.of(ByteBuffer.wrap(data), false);
}
@Override
public long availableTo(@Nonnull OutputStream dst) throws IORuntimeException {
return readTo(dst, IOChecker.availableChecker());
}
@Override
public long availableTo(
@Nonnull OutputStream dst, long len
) throws IllegalArgumentException, IORuntimeException {
return readTo(dst, len, IOChecker.availableChecker());
}
@Override
public long availableTo(@Nonnull WritableByteChannel dst) throws IORuntimeException {
return readTo(dst, IOChecker.availableChecker());
}
@Override
public long availableTo(
@Nonnull WritableByteChannel dst, long len
) throws IllegalArgumentException, IORuntimeException {
return readTo(dst, len, IOChecker.availableChecker());
}
@Override
public int availableTo(byte @Nonnull [] dst) throws IORuntimeException {
return readTo(dst, IOChecker.availableChecker());
}
@Override
public int availableTo(
byte @Nonnull [] dst, int off, int len
) throws IndexOutOfBoundsException, IORuntimeException {
return readTo(dst, off, len, IOChecker.availableChecker());
}
@Override
public int availableTo(@Nonnull ByteBuffer dst) throws IORuntimeException {
return readTo(dst, IOChecker.availableChecker());
}
@Override
public int availableTo(@Nonnull ByteBuffer dst, int len) throws IllegalArgumentException, IORuntimeException {
return readTo(dst, len, IOChecker.availableChecker());
}
private long readTo(@Nonnull OutputStream dst, ReadChecker readChecker) throws IORuntimeException {
return IOKit.readTo0(src, dst, bufSize, readChecker);
}
private long readTo(
@Nonnull OutputStream dst, long len, ReadChecker readChecker
) throws IllegalArgumentException, IORuntimeException {
IOChecker.checkLen(len);
return IOKit.readTo0(src, dst, len, bufSize, readChecker);
}
private long readTo(@Nonnull WritableByteChannel dst, ReadChecker readChecker) throws IORuntimeException {
return IOKit.readTo0(src, dst, bufSize, readChecker);
}
private long readTo(
@Nonnull WritableByteChannel dst, long len, ReadChecker readChecker
) throws IllegalArgumentException, IORuntimeException {
IOChecker.checkLen(len);
return IOKit.readTo0(src, dst, len, bufSize, readChecker);
}
private int readTo(
byte @Nonnull [] dst, ReadChecker readChecker
) throws IORuntimeException {
return IOKit.readTo0(src, dst, 0, dst.length, readChecker);
}
private int readTo(
byte @Nonnull [] dst, int off, int len, ReadChecker readChecker
) throws IndexOutOfBoundsException, IORuntimeException {
IOChecker.checkOffLen(off, len, dst.length);
return IOKit.readTo0(src, dst, off, len, readChecker);
}
private int readTo(
@Nonnull ByteBuffer dst, ReadChecker readChecker
) throws IORuntimeException {
return IOKit.readTo0(src, dst, dst.remaining(), readChecker);
}
private int readTo(
@Nonnull ByteBuffer dst, int len, ReadChecker readChecker
) throws IllegalArgumentException, IORuntimeException {
IOChecker.checkLen(len);
return IOKit.readTo0(src, dst, len, readChecker);
}
@Override
public boolean markSupported() {
return src.markSupported();
}
@Override
public void mark() throws IORuntimeException {
try {
src.mark(Integer.MAX_VALUE);
} catch (Exception e) {
throw new IORuntimeException(e);
}
}
@Override
public void reset() throws IORuntimeException {
try {
src.reset();
} catch (Exception e) {
throw new IORuntimeException(e);
}
}
@Override
public void close() throws IORuntimeException {
try {
src.close();
} catch (Exception e) {
throw new IORuntimeException(e);
}
}
@Override
public @Nonnull InputStream asInputStream() {
return src;
}
}
private static final class ByteChannelReader implements ByteReader {
private final @Nonnull ReadableByteChannel src;
private final int bufSize;
private ByteChannelReader(@Nonnull ReadableByteChannel src, int bufSize) {
this.src = src;
this.bufSize = bufSize;
}
@Override
public int ready() {
return 0;
}
@Override
public @Nonnull ByteSegment read(int len) throws IllegalArgumentException, IORuntimeException {
IOChecker.checkLen(len);
ByteBuffer data = IOKit.read0(src, len, bufSize, IOChecker.endChecker());
if (data == null) {
return ByteSegment.empty(true);
}
return ByteSegment.of(data, data.remaining() < len);
}
@Override
public @Nullable ByteBuffer read() throws IORuntimeException {
return IOKit.read0(src, bufSize, IOChecker.endChecker());
}
@Override
public long skip(long len) throws IllegalArgumentException, IORuntimeException {
IOChecker.checkSkip(len);
if (len == 0) {
return 0;
}
return skip0(len);
}
private long skip0(long len) {
long hasRead = 0;
int onceBufSize = (int) Math.min(len, bufSize);
ByteBuffer buf = ByteBuffer.allocate(onceBufSize);
while (hasRead < len) {
int onceSize = IOKit.readTo0(src, buf, (int) Math.min(onceBufSize, len - hasRead), IOChecker.endChecker());
if (onceSize < 0) {
return hasRead;
}
hasRead += onceSize;
}
return hasRead;
}
@Override
public long readTo(@Nonnull OutputStream dst) throws IORuntimeException {
return readTo(dst, IOChecker.endChecker());
}
@Override
public long readTo(@Nonnull OutputStream dst, long len) throws IllegalArgumentException, IORuntimeException {
return readTo(dst, len, IOChecker.endChecker());
}
@Override
public long readTo(@Nonnull WritableByteChannel dst) throws IORuntimeException {
return readTo(dst, IOChecker.endChecker());
}
@Override
public long readTo(
@Nonnull WritableByteChannel dst, long len
) throws IllegalArgumentException, IORuntimeException {
return readTo(dst, len, IOChecker.endChecker());
}
@Override
public int readTo(byte @Nonnull [] dst) throws IORuntimeException {
return readTo(dst, IOChecker.endChecker());
}
@Override
public int readTo(byte @Nonnull [] dst, int off, int len) throws IndexOutOfBoundsException, IORuntimeException {
return readTo(dst, off, len, IOChecker.endChecker());
}
@Override
public int readTo(@Nonnull ByteBuffer dst) throws IORuntimeException {
return readTo(dst, IOChecker.endChecker());
}
@Override
public int readTo(@Nonnull ByteBuffer dst, int len) throws IllegalArgumentException, IORuntimeException {
return readTo(dst, len, IOChecker.endChecker());
}
@Override
public @Nonnull ByteSegment available(int len) throws IllegalArgumentException, IORuntimeException {
IOChecker.checkLen(len);
ByteBuffer data = IOKit.read0(src, len, bufSize, IOChecker.availableChecker());
if (data == null) {
return ByteSegment.empty(true);
}
return ByteSegment.of(data, false);
}
@Override
public @Nonnull ByteSegment available() throws IORuntimeException {
ByteBuffer data = IOKit.read0(src, bufSize, IOChecker.availableChecker());
if (data == null) {
return ByteSegment.empty(true);
}
return ByteSegment.of(data, false);
}
@Override
public long availableTo(@Nonnull OutputStream dst) throws IORuntimeException {
return readTo(dst, IOChecker.availableChecker());
}
@Override
public long availableTo(
@Nonnull OutputStream dst, long len
) throws IllegalArgumentException, IORuntimeException {
return readTo(dst, len, IOChecker.availableChecker());
}
@Override
public long availableTo(@Nonnull WritableByteChannel dst) throws IORuntimeException {
return readTo(dst, IOChecker.availableChecker());
}
@Override
public long availableTo(
@Nonnull WritableByteChannel dst, long len
) throws IllegalArgumentException, IORuntimeException {
return readTo(dst, len, IOChecker.availableChecker());
}
@Override
public int availableTo(byte @Nonnull [] dst) throws IORuntimeException {
return readTo(dst, IOChecker.availableChecker());
}
@Override
public int availableTo(
byte @Nonnull [] dst, int off, int len
) throws IndexOutOfBoundsException, IORuntimeException {
return readTo(dst, off, len, IOChecker.availableChecker());
}
@Override
public int availableTo(@Nonnull ByteBuffer dst) throws IORuntimeException {
return readTo(dst, IOChecker.availableChecker());
}
@Override
public int availableTo(@Nonnull ByteBuffer dst, int len) throws IllegalArgumentException, IORuntimeException {
return readTo(dst, len, IOChecker.availableChecker());
}
private long readTo(@Nonnull OutputStream dst, ReadChecker readChecker) throws IORuntimeException {
return IOKit.readTo0(src, dst, bufSize, readChecker);
}
private long readTo(
@Nonnull OutputStream dst, long len, ReadChecker readChecker
) throws IllegalArgumentException, IORuntimeException {
IOChecker.checkLen(len);
return IOKit.readTo0(src, dst, len, bufSize, readChecker);
}
private long readTo(@Nonnull WritableByteChannel dst, ReadChecker readChecker) throws IORuntimeException {
return IOKit.readTo0(src, dst, bufSize, readChecker);
}
private long readTo(
@Nonnull WritableByteChannel dst, long len, ReadChecker readChecker
) throws IllegalArgumentException, IORuntimeException {
IOChecker.checkLen(len);
return IOKit.readTo0(src, dst, len, bufSize, readChecker);
}
private int readTo(
byte @Nonnull [] dst, ReadChecker readChecker
) throws IORuntimeException {
return IOKit.readTo0(src, ByteBuffer.wrap(dst, 0, dst.length), readChecker);
}
private int readTo(
byte @Nonnull [] dst, int off, int len, ReadChecker readChecker
) throws IndexOutOfBoundsException, IORuntimeException {
return IOKit.readTo0(src, ByteBuffer.wrap(dst, off, len), readChecker);
}
private int readTo(
@Nonnull ByteBuffer dst, ReadChecker readChecker
) throws IORuntimeException {
return IOKit.readTo0(src, dst, dst.remaining(), readChecker);
}
private int readTo(
@Nonnull ByteBuffer dst, int len, ReadChecker readChecker
) throws IllegalArgumentException, IORuntimeException {
IOChecker.checkLen(len);
return IOKit.readTo0(src, dst, len, readChecker);
}
@Override
public boolean markSupported() {
return false;
}
@Override
public void mark() throws IORuntimeException {
throw new IORuntimeException("Mark/Reset is unsupported.");
}
@Override
public void reset() throws IORuntimeException {
throw new IORuntimeException("Mark/Reset is unsupported.");
}
@Override
public void close() throws IORuntimeException {
try {
src.close();
} catch (Exception e) {
throw new IORuntimeException(e);
}
}
@Override
public @Nonnull InputStream asInputStream() {
return Channels.newInputStream(src);
}
}
private static abstract class InMemoryReader implements ByteReader {
@Override
public @Nonnull ByteSegment available(int len) throws IllegalArgumentException, IORuntimeException {
return read(len);
}
@Override
public long availableTo(@Nonnull OutputStream dst) throws IORuntimeException {
return readTo(dst);
}
@Override
public long availableTo(@Nonnull OutputStream dst, long len) throws IllegalArgumentException, IORuntimeException {
return readTo(dst, len);
}
@Override
public long availableTo(@Nonnull WritableByteChannel dst) throws IORuntimeException {
return readTo(dst);
}
@Override
public long availableTo(@Nonnull WritableByteChannel dst, long len) throws IllegalArgumentException, IORuntimeException {
return readTo(dst, len);
}
@Override
public int availableTo(byte @Nonnull [] dst) throws IORuntimeException {
return readTo(dst);
}
@Override
public int availableTo(byte @Nonnull [] dst, int off, int len) throws IndexOutOfBoundsException, IORuntimeException {
return readTo(dst, off, len);
}
@Override
public int availableTo(@Nonnull ByteBuffer dst) throws IORuntimeException {
return readTo(dst);
}
@Override
public int availableTo(@Nonnull ByteBuffer dst, int len) throws IllegalArgumentException, IORuntimeException {
return readTo(dst, len);
}
}
private static final class ByteArrayReader extends InMemoryReader {
private final byte @Nonnull [] src;
private int pos;
private final int end;
private int mark;
private ByteArrayReader(byte @Nonnull [] src, int off, int len) {
this.src = src;
this.pos = off;
this.end = off + len;
this.mark = pos;
}
@Override
public int ready() {
return end - pos;
}
@Override
public @Nonnull ByteSegment read(int len) throws IllegalArgumentException {
IOChecker.checkLen(len);
if (len == 0) {
return ByteSegment.empty(false);
}
if (pos == end) {
return ByteSegment.empty(true);
}
int remaining = end - pos;
int actualLen = Math.min(remaining, len);
ByteBuffer data = ByteBuffer.wrap(src, pos, actualLen).slice();
pos += actualLen;
return ByteSegment.of(data, remaining <= len);
}
@Override
public @Nullable ByteBuffer read() throws IORuntimeException {
if (pos >= end) {
return null;
}
ByteBuffer ret = ByteBuffer.wrap(src, pos, end - pos);
pos = end;
return ret;
}
@Override
public long skip(long len) throws IllegalArgumentException {
IOChecker.checkSkip(len);
return skip0(len);
}
private long skip0(long len) {
if (len == 0) {
return 0;
}
if (pos == end) {
return 0;
}
int remaining = end - pos;
int skipped = (int) Math.min(remaining, len);
pos += skipped;
return skipped;
}
@Override
public long readTo(@Nonnull OutputStream dst) throws IORuntimeException {
if (pos == end) {
return -1;
}
try {
int remaining = end - pos;
dst.write(src, pos, remaining);
pos += remaining;
return remaining;
} catch (IOException e) {
throw new IORuntimeException(e);
}
}
@Override
public long readTo(@Nonnull OutputStream dst, long len) throws IllegalArgumentException, IORuntimeException {
IOChecker.checkLen(len);
if (len == 0) {
return 0;
}
if (pos == end) {
return -1;
}
try {
int remaining = end - pos;
int actualLen = (int) Math.min(remaining, len);
dst.write(src, pos, actualLen);
pos += actualLen;
return actualLen;
} catch (IOException e) {
throw new IORuntimeException(e);
}
}
@Override
public long readTo(@Nonnull WritableByteChannel dst) throws IORuntimeException {
if (pos == end) {
return -1;
}
int remaining = end - pos;
ByteBuffer buf = ByteBuffer.wrap(src, pos, remaining);
int ret = BufferKit.readTo(buf, dst);
pos += ret;
return ret;
}
@Override
public long readTo(
@Nonnull WritableByteChannel dst, long len
) throws IllegalArgumentException, IORuntimeException {
IOChecker.checkLen(len);
if (len == 0) {
return 0;
}
if (pos == end) {
return -1;
}
int remaining = end - pos;
int actualLen = (int) Math.min(remaining, len);
ByteBuffer buf = ByteBuffer.wrap(src, pos, actualLen);
int ret = BufferKit.readTo(buf, dst);
pos += ret;
return ret;
}
@Override
public int readTo(byte @Nonnull [] dst) {
return readTo0(dst, 0, dst.length);
}
@Override
public int readTo(byte @Nonnull [] dst, int off, int len) throws IndexOutOfBoundsException {
IOChecker.checkOffLen(off, len, dst.length);
return readTo0(dst, off, len);
}
private int readTo0(byte @Nonnull [] dst, int off, int len) {
if (len == 0) {
return 0;
}
if (pos == end) {
return -1;
}
int remaining = end - pos;
int copySize = Math.min(remaining, len);
System.arraycopy(src, pos, dst, off, copySize);
pos += copySize;
return copySize;
}
@Override
public int readTo(@Nonnull ByteBuffer dst) throws IORuntimeException {
if (dst.remaining() == 0) {
return 0;
}
if (pos == end) {
return -1;
}
int remaining = end - pos;
int putSize = Math.min(remaining, dst.remaining());
return putTo0(dst, putSize);
}
@Override
public int readTo(@Nonnull ByteBuffer dst, int len) throws IllegalArgumentException, IORuntimeException {
IOChecker.checkLen(len);
if (len == 0) {
return 0;
}
if (dst.remaining() == 0) {
return 0;
}
if (pos == end) {
return -1;
}
int remaining = end - pos;
int putSize = MathKit.min(remaining, dst.remaining(), len);
return putTo0(dst, putSize);
}
private int putTo0(@Nonnull ByteBuffer dst, int putSize) throws IORuntimeException {
try {
dst.put(src, pos, putSize);
pos += putSize;
return putSize;
} catch (Exception e) {
throw new IORuntimeException(e);
}
}
@Override
public @Nonnull ByteSegment available() throws IORuntimeException {
return read(end - pos);
}
@Override
public boolean markSupported() {
return true;
}
@Override
public void mark() {
mark = pos;
}
@Override
public void reset() {
pos = mark;
}
@Override
public void close() {
}
}
private static final class ByteBufferReader extends InMemoryReader {
private final @Nonnull ByteBuffer src;
private ByteBufferReader(@Nonnull ByteBuffer src) {
this.src = src;
}
@Override
public int ready() {
return src.remaining();
}
@Override
public @Nonnull ByteSegment read(int len) throws IllegalArgumentException, IORuntimeException {
IOChecker.checkLen(len);
if (len == 0) {
return ByteSegment.empty(false);
}
if (!src.hasRemaining()) {
return ByteSegment.empty(true);
}
int pos = src.position();
int limit = src.limit();
int newPos = Math.min(pos + len, limit);
src.limit(newPos);
ByteBuffer data = src.slice();
src.position(newPos);
src.limit(limit);
return ByteSegment.of(data, newPos >= limit);
}
@Override
public @Nullable ByteBuffer read() throws IORuntimeException {
if (!src.hasRemaining()) {
return null;
}
ByteBuffer ret = src.slice();
src.position(src.limit());
return ret;
}
@Override
public long skip(long len) throws IllegalArgumentException {
IOChecker.checkSkip(len);
return skip0(len);
}
private long skip0(long len) {
if (len == 0) {
return 0;
}
if (!src.hasRemaining()) {
return 0;
}
int pos = src.position();
int newPos = (int) Math.min(pos + len, src.limit());
src.position(newPos);
return newPos - pos;
}
@Override
public long readTo(@Nonnull OutputStream dst) throws IORuntimeException {
return BufferKit.readTo(src, dst);
}
@Override
public long readTo(@Nonnull OutputStream dst, long len) throws IllegalArgumentException, IORuntimeException {
IOChecker.checkLen(len);
int actualLen = (int) Math.min(Integer.MAX_VALUE, len);
return BufferKit.readTo0(src, dst, actualLen);
}
@Override
public long readTo(@Nonnull WritableByteChannel dst) throws IORuntimeException {
return BufferKit.readTo(src, dst);
}
@Override
public long readTo(
@Nonnull WritableByteChannel dst, long len
) throws IllegalArgumentException, IORuntimeException {
IOChecker.checkLen(len);
int actualLen = (int) Math.min(Integer.MAX_VALUE, len);
return BufferKit.readTo0(src, dst, actualLen);
}
@Override
public int readTo(byte @Nonnull [] dst) {
return BufferKit.readTo(src, dst);
}
@Override
public int readTo(byte @Nonnull [] dst, int off, int len) throws IndexOutOfBoundsException {
return BufferKit.readTo(src, dst, off, len);
}
@Override
public int readTo(@Nonnull ByteBuffer dst) throws IORuntimeException {
return BufferKit.readTo(src, dst);
}
@Override
public int readTo(@Nonnull ByteBuffer dst, int len) throws IllegalArgumentException, IORuntimeException {
return BufferKit.readTo(src, dst, len);
}
@Override
public @Nonnull ByteSegment available() throws IORuntimeException {
return read(src.remaining());
}
@Override
public boolean markSupported() {
return true;
}
@Override
public void mark() {
src.mark();
}
@Override
public void reset() throws IORuntimeException {
try {
src.reset();
} catch (Exception e) {
throw new IORuntimeException(e);
}
}
@Override
public void close() {
}
}
private static final class LimitedReader implements ByteReader {
private final @Nonnull ByteReader src;
private final long limit;
private long pos = 0;
private long mark = 0;
private LimitedReader(@Nonnull ByteReader src, long limit) {
this.src = src;
this.limit = limit;
}
@Override
public int ready() throws IORuntimeException {
return Math.min(src.ready(), MathKit.safeInt(limit - pos));
}
@Override
public @Nonnull ByteSegment read(int len) throws IllegalArgumentException, IORuntimeException {
return read(len, false);
}
@Override
public @Nullable ByteBuffer read() throws IORuntimeException {
if (pos >= limit) {
return null;
}
int len = MathKit.safeInt(limit - pos);
return read(len).data();
}
@Override
public long skip(long len) throws IllegalArgumentException, IORuntimeException {
IOChecker.checkSkip(len);
if (len == 0) {
return 0;
}
if (pos >= limit) {
return 0;
}
int actualLen = (int) Math.min(len, limit - pos);
long skipped = src.skip(actualLen);
pos += skipped;
return skipped;
}
@Override
public long readTo(@Nonnull OutputStream dst) throws IORuntimeException {
if (pos >= limit) {
return -1;
}
long readSize = src.readTo(dst, limit - pos);
if (readSize < 0) {
return readSize;
}
pos += readSize;
return readSize;
}
@Override
public long readTo(@Nonnull OutputStream dst, long len) throws IllegalArgumentException, IORuntimeException {
IOChecker.checkLen(len);
if (len == 0) {
return 0;
}
if (pos >= limit) {
return -1;
}
int actualLen = (int) Math.min(len, limit - pos);
long readSize = src.readTo(dst, actualLen);
if (readSize < 0) {
return readSize;
}
pos += readSize;
return readSize;
}
@Override
public long readTo(@Nonnull WritableByteChannel dst) throws IORuntimeException {
if (pos >= limit) {
return -1;
}
long readSize = src.readTo(dst, limit - pos);
if (readSize < 0) {
return readSize;
}
pos += readSize;
return readSize;
}
@Override
public long readTo(
@Nonnull WritableByteChannel dst, long len
) throws IllegalArgumentException, IORuntimeException {
IOChecker.checkLen(len);
if (len == 0) {
return 0;
}
if (pos >= limit) {
return -1;
}
int actualLen = (int) Math.min(len, limit - pos);
long readSize = src.readTo(dst, actualLen);
if (readSize < 0) {
return readSize;
}
pos += readSize;
return readSize;
}
@Override
public int readTo(byte @Nonnull [] dst) throws IORuntimeException {
return readTo(dst, 0, dst.length);
}
@Override
public int readTo(
byte @Nonnull [] dst, int off, int len
) throws IndexOutOfBoundsException, IORuntimeException {
IOChecker.checkOffLen(off, len, dst.length);
if (len == 0) {
return 0;
}
if (pos >= limit) {
return -1;
}
int actualLen = (int) Math.min(len, limit - pos);
int readSize = src.readTo(dst, off, actualLen);
if (readSize < 0) {
return readSize;
}
pos += readSize;
return readSize;
}
@Override
public int readTo(@Nonnull ByteBuffer dst) throws IORuntimeException {
return readTo(dst, dst.remaining());
}
@Override
public int readTo(@Nonnull ByteBuffer dst, int len) throws IllegalArgumentException, IORuntimeException {
IOChecker.checkLen(len);
if (len == 0) {
return 0;
}
if (!dst.hasRemaining()) {
return 0;
}
if (pos >= limit) {
return -1;
}
int actualLen = (int) MathKit.min(len, limit - pos, dst.remaining());
int readSize = src.readTo(dst, actualLen);
if (readSize < 0) {
return readSize;
}
pos += readSize;
return readSize;
}
@Override
public @Nonnull ByteSegment available(int len) throws IllegalArgumentException, IORuntimeException {
return read(len, true);
}
@Override
public @Nonnull ByteSegment available() throws IORuntimeException {
return available(MathKit.safeInt(limit - pos));
}
@Override
public long availableTo(@Nonnull OutputStream dst) throws IORuntimeException {
if (pos >= limit) {
return -1;
}
long readSize = src.availableTo(dst, limit - pos);
if (readSize <= 0) {
return readSize;
}
pos += readSize;
return readSize;
}
@Override
public long availableTo(
@Nonnull OutputStream dst, long len
) throws IllegalArgumentException, IORuntimeException {
IOChecker.checkLen(len);
if (len == 0) {
return 0;
}
if (pos >= limit) {
return -1;
}
int actualLen = (int) Math.min(len, limit - pos);
long readSize = src.availableTo(dst, actualLen);
if (readSize <= 0) {
return readSize;
}
pos += readSize;
return readSize;
}
@Override
public long availableTo(@Nonnull WritableByteChannel dst) throws IORuntimeException {
if (pos >= limit) {
return -1;
}
long readSize = src.availableTo(dst, limit - pos);
if (readSize <= 0) {
return readSize;
}
pos += readSize;
return readSize;
}
@Override
public long availableTo(
@Nonnull WritableByteChannel dst, long len
) throws IllegalArgumentException, IORuntimeException {
IOChecker.checkLen(len);
if (len == 0) {
return 0;
}
if (pos >= limit) {
return -1;
}
int actualLen = (int) Math.min(len, limit - pos);
long readSize = src.availableTo(dst, actualLen);
if (readSize <= 0) {
return readSize;
}
pos += readSize;
return readSize;
}
@Override
public int availableTo(byte @Nonnull [] dst) throws IORuntimeException {
return availableTo(dst, 0, dst.length);
}
@Override
public int availableTo(
byte @Nonnull [] dst, int off, int len
) throws IndexOutOfBoundsException, IORuntimeException {
IOChecker.checkOffLen(off, len, dst.length);
if (len == 0) {
return 0;
}
if (pos >= limit) {
return -1;
}
int actualLen = (int) Math.min(len, limit - pos);
int readSize = src.availableTo(dst, off, actualLen);
if (readSize <= 0) {
return readSize;
}
pos += readSize;
return readSize;
}
@Override
public int availableTo(@Nonnull ByteBuffer dst) throws IORuntimeException {
return availableTo(dst, dst.remaining());
}
@Override
public int availableTo(@Nonnull ByteBuffer dst, int len) throws IllegalArgumentException, IORuntimeException {
IOChecker.checkLen(len);
if (len == 0) {
return 0;
}
if (!dst.hasRemaining()) {
return 0;
}
if (pos >= limit) {
return -1;
}
int actualLen = (int) MathKit.min(len, limit - pos, dst.remaining());
int readSize = src.availableTo(dst, actualLen);
if (readSize <= 0) {
return readSize;
}
pos += readSize;
return readSize;
}
private @Nonnull ByteSegment read(int len, boolean available) throws IllegalArgumentException, IORuntimeException {
IOChecker.checkLen(len);
if (len == 0) {
return ByteSegment.empty(false);
}
if (pos >= limit) {
return ByteSegment.empty(true);
}
int maxLen = (int) Math.min(len, limit - pos);
ByteSegment segment = available ? src.available(maxLen) : src.read(maxLen);
pos += segment.data().remaining();
if (!segment.end()) {
if (pos >= limit) {
return newSeg(segment.data(), true);
}
}
return segment;
}
@Override
public boolean markSupported() {
return src.markSupported();
}
@Override
public void mark() throws IORuntimeException {
src.mark();
mark = pos;
}
@Override
public void reset() throws IORuntimeException {
src.reset();
pos = mark;
}
@Override
public void close() throws IORuntimeException {
src.close();
}
}
private static final class AsInputStream extends DoReadStream {
private final @Nonnull ByteReader in;
private byte[] oneByte;
private AsInputStream(@Nonnull ByteReader in) {
this.in = in;
}
@Override
public int read() throws IOException {
try {
if (oneByte == null) {
oneByte = new byte[1];
}
int ret = in.readTo(oneByte);
return ret < 0 ? -1 : oneByte[0] & 0xFF;
} catch (Exception e) {
throw new IOException(e);
}
}
@Override
protected int doRead(byte @Nonnull [] b, int off, int len) throws IOException {
try {
return in.readTo(b, off, len);
} catch (Exception e) {
throw new IOException(e);
}
}
@Override
public long skip(long n) throws IOException {
if (n <= 0) {
return 0;
}
try {
return in.skip(n);
} catch (Exception e) {
throw new IOException(e);
}
}
@Override
public boolean markSupported() {
return in.markSupported();
}
@Override
public void mark(int readAheadLimit) {
Fs.uncheck(in::mark);
}
@Override
public void reset() throws IOException {
try {
in.reset();
} catch (Exception e) {
throw new IOException(e);
}
}
@Override
public void close() throws IOException {
try {
in.close();
} catch (Exception e) {
throw new IOException(e);
}
}
@Override
public int available() {
return in.ready();
}
}
private ByteReaderBack() {
}
}