From 410ce17498cd5820609300e3a6dc7d6b10e6f447 Mon Sep 17 00:00:00 2001 From: Collin Smith Date: Sat, 9 Sep 2023 00:19:00 -0700 Subject: [PATCH] Created ByteInputStream variant of ByteInput which wraps an InputStream but without many features from ByteInput which are not required at this time, may need to expand functionality later to make stream variant indistinguishable from normal variant Created additional constructors for InvalidFormat for ByteInputStream --- .../java/com/riiablo/io/ByteInputStream.java | 257 ++++++++++++++++++ .../java/com/riiablo/io/InvalidFormat.java | 12 + 2 files changed, 269 insertions(+) create mode 100644 core/src/main/java/com/riiablo/io/ByteInputStream.java diff --git a/core/src/main/java/com/riiablo/io/ByteInputStream.java b/core/src/main/java/com/riiablo/io/ByteInputStream.java new file mode 100644 index 00000000..87c12795 --- /dev/null +++ b/core/src/main/java/com/riiablo/io/ByteInputStream.java @@ -0,0 +1,257 @@ +package com.riiablo.io; + +import java.io.DataInput; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import org.apache.commons.io.input.SwappedDataInputStream; +import org.apache.commons.lang3.exception.ExceptionUtils; + +import static com.riiablo.util.ImplUtils.unsupported; + +public class ByteInputStream { + public static ByteInputStream wrap(InputStream in) { + return wrap(in, 0); + } + + public static ByteInputStream wrap(InputStream in, int offset) { + return wrap(in, 0, Integer.MAX_VALUE); + } + + public static ByteInputStream wrap(InputStream in, int offset, int length) { + return new ByteInputStream(in, offset, length); + } + + private final DataInput in; + private final int offset; + private final int length; + private int readerIndex; + private int mark; + + ByteInputStream(InputStream in, int offset, int length) { + this.in = new SwappedDataInputStream(in); + this.offset = offset; + this.length = length; + updateMark(); + } + + public void resetMark() { + readerIndex = 0; + } + + public int updateMark() { + return mark = offset + readerIndex; + } + + public int mark() { + return mark; + } + + public int bytesRead() { + return readerIndex; + } + + public int bytesRemaining() { + return length - readerIndex; + } + + public boolean aligned() { + return true; + } + + public ByteInputStream skipBytes(int bytes) { + incrementBitsRead((long) bytes * Byte.SIZE); + try { + /* keeps skipping chunks until length or eof reached, whichever first */ + int totalSkipped = 0, skipped; + while ((totalSkipped += (skipped = in.skipBytes(bytes - totalSkipped))) < bytes && skipped > 0); + if (totalSkipped < bytes) throw new EOFException(); + return this; + } catch (EOFException t) { + throw new EndOfInput(t); + } catch (IOException t) { + return ExceptionUtils.rethrow(t); + } + } + + public ByteInputStream skipUntil(byte[] signature) { + return unsupported("not supported for input streams"); + } + + public ByteInputStream readSignature(byte[] signature) { + return unsupported("not supported for input streams"); + } + + public ByteInputStream readSlice(long numBytes) { + return unsupported("not supported for input streams"); + } + + public ByteInputStream slice(long numBytes) { + return unsupported("not supported for input streams"); + } + + @Deprecated + public byte[] duplicate(int offset, int len) { + return unsupported("not supported for input streams"); + } + + int _read8u() { + return unsupported("not supported for input streams"); + } + + long incrementBitsRead(long bits) { + assert (((int) bits) & 0x7) == 0 : "not aligned"; + updateMark(); + readerIndex += (int) (bits >> 3L); + return 0; + } + + long decrementBitsRead(long bits) { + return unsupported("not supported for input streams"); + } + + public short read8u() { + assert aligned() : "not aligned"; + try { + incrementBitsRead(Byte.SIZE); + return (short) in.readUnsignedByte(); + } catch (EOFException t) { + throw new EndOfInput(t); + } catch (IOException t) { + return ExceptionUtils.rethrow(t); + } + } + + public int read16u() { + assert aligned() : "not aligned"; + try { + incrementBitsRead(Short.SIZE); + return in.readUnsignedShort(); + } catch (EOFException t) { + throw new EndOfInput(t); + } catch (IOException t) { + return ExceptionUtils.rethrow(t); + } + } + + public long read32u() { + assert aligned() : "not aligned"; + try { + incrementBitsRead(Integer.SIZE); + return in.readInt() & 0xFFFFFFFFL; + } catch (EOFException t) { + throw new EndOfInput(t); + } catch (IOException t) { + return ExceptionUtils.rethrow(t); + } + } + + public boolean readBoolean() { + return read8() != 0; + } + + public byte read8() { + assert aligned() : "not aligned"; + try { + incrementBitsRead(Byte.SIZE); + return in.readByte(); + } catch (EOFException t) { + throw new EndOfInput(t); + } catch (IOException t) { + return ExceptionUtils.rethrow(t); + } + } + + public short read16() { + assert aligned() : "not aligned"; + try { + incrementBitsRead(Short.SIZE); + return in.readShort(); + } catch (EOFException t) { + throw new EndOfInput(t); + } catch (IOException t) { + return ExceptionUtils.rethrow(t); + } + } + + public int read32() { + assert aligned() : "not aligned"; + try { + incrementBitsRead(Integer.SIZE); + return in.readInt(); + } catch (EOFException t) { + throw new EndOfInput(t); + } catch (IOException t) { + return ExceptionUtils.rethrow(t); + } + } + + public long read64() { + assert aligned() : "not aligned"; + try { + incrementBitsRead(Long.SIZE); + return in.readLong(); + } catch (EOFException t) { + throw new EndOfInput(t); + } catch (IOException t) { + return ExceptionUtils.rethrow(t); + } + } + + public byte readSafe8u() { + assert aligned() : "not aligned"; + final short value = read8u(); // increments bits + return BitConstraints.safe8u(mark, value); + } + + public short readSafe16u() { + assert aligned() : "not aligned"; + final int value = read16u(); // increments bits + return BitConstraints.safe16u(mark, value); + } + + public int readSafe32u() { + assert aligned() : "not aligned"; + final long value = read32u(); // increments bits + return BitConstraints.safe32u(mark, value); + } + + public long readSafe64u() { + assert aligned() : "not aligned"; + final long value = read64(); // increments bits + return BitConstraints.safe64u(mark, value); + } + + public byte[] readBytes(int len) { + return readBytes(new byte[len]); + } + + public byte[] readBytes(byte[] dst) { + return readBytes(dst, 0, dst.length); + } + + public byte[] readBytes(byte[] dst, int dstOffset, int len) { + assert aligned() : "not aligned"; + try { + incrementBitsRead((long) len * Byte.SIZE); + in.readFully(dst, dstOffset, len); + return dst; + } catch (IndexOutOfBoundsException | EOFException t) { + throw new EndOfInput(t); + } catch (IOException t) { + return ExceptionUtils.rethrow(t); + } + } + + public String readString(int len) { + return unsupported("not supported for input streams"); + } + + public String readString(int maxLen, boolean nullTerminated) { + return unsupported("not supported for input streams"); + } + + public String readString() { + return unsupported("not supported for input streams"); + } +} diff --git a/core/src/main/java/com/riiablo/io/InvalidFormat.java b/core/src/main/java/com/riiablo/io/InvalidFormat.java index d182d871..8f785525 100644 --- a/core/src/main/java/com/riiablo/io/InvalidFormat.java +++ b/core/src/main/java/com/riiablo/io/InvalidFormat.java @@ -15,6 +15,18 @@ public class InvalidFormat extends RuntimeException { this(in.mark(), message, cause); } + public InvalidFormat(ByteInputStream in, Throwable cause) { + this(in.mark(), "Invalid format", cause); + } + + public InvalidFormat(ByteInputStream in, String message) { + this(in.mark(), message, null); + } + + public InvalidFormat(ByteInputStream in, String message, Throwable cause) { + this(in.mark(), message, cause); + } + InvalidFormat(long offset, String message, Throwable cause) { super(message + " +0x" + Long.toHexString(offset), cause); this.offset = offset;