diff --git a/core/src/com/riiablo/io/BitConstraints.java b/core/src/com/riiablo/io/BitConstraints.java index f134a08c..e9cb8579 100644 --- a/core/src/com/riiablo/io/BitConstraints.java +++ b/core/src/com/riiablo/io/BitConstraints.java @@ -59,4 +59,36 @@ class BitConstraints { public static int validateAscii(int bits) { return _validateSize(Byte.SIZE - 1, Byte.SIZE, bits); } + + public static byte safe8u(short i) { + if (!BitUtils.isUnsigned(i, Byte.SIZE)) { + throw new SafeUnsigned(i); + } + + return (byte) i; + } + + public static short safe16u(int i) { + if (!BitUtils.isUnsigned(i, Short.SIZE)) { + throw new SafeUnsigned(i); + } + + return (short) i; + } + + public static int safe32u(long i) { + if (!BitUtils.isUnsigned(i, Integer.SIZE)) { + throw new SafeUnsigned(i); + } + + return (int) i; + } + + public static long safe64u(long i) { + if (!BitUtils.isUnsigned(i, Long.SIZE)) { + throw new SafeUnsigned(i); + } + + return (long) i; + } } diff --git a/core/src/com/riiablo/io/ByteInput.java b/core/src/com/riiablo/io/ByteInput.java index dd2468a6..475fd133 100644 --- a/core/src/com/riiablo/io/ByteInput.java +++ b/core/src/com/riiablo/io/ByteInput.java @@ -285,6 +285,78 @@ public class ByteInput { } } + /** + * Reads an unsigned byte as a {@code byte}. + * + * @throws SafeUnsigned if the read value is larger than 7 bits. + * + * @see #read8u() + */ + public byte readSafe8u() { + assert aligned() : "not aligned"; + try { + incrementBitsRead(Byte.SIZE); + final short value = read8u(); + return BitConstraints.safe8u(value); + } catch (IndexOutOfBoundsException t) { + throw new EndOfInput(t); + } + } + + /** + * Reads an unsigned 16-bit short integer as a {@code short}. + * + * @throws SafeUnsigned if the read value is larger than 15 bits. + * + * @see #read16u() + */ + public short readSafe16u() { + assert aligned() : "not aligned"; + try { + incrementBitsRead(Short.SIZE); + final int value = read16u(); + return BitConstraints.safe16u(value); + } catch (IndexOutOfBoundsException t) { + throw new EndOfInput(t); + } + } + + /** + * Reads an unsigned 32-bit integer as an {@code int}. + * + * @throws SafeUnsigned if the read value is larger than 31 bits. + * + * @see #read32u() + */ + public long readSafe32u() { + assert aligned() : "not aligned"; + try { + incrementBitsRead(Integer.SIZE); + final long value = read32u(); + return BitConstraints.safe32u(value); + } catch (IndexOutOfBoundsException t) { + throw new EndOfInput(t); + } + } + + /** + * Reads an unsigned 64-bit long integer as a {@code long}. + * + * @throws SafeUnsigned if the read value is larger than 63 bits. + * + * @see #read32u() + */ + public long readSafe64u() { + assert aligned() : "not aligned"; + try { + incrementBitsRead(Long.SIZE); + final long value = read32u(); + return BitConstraints.safe32u(value); + } catch (IndexOutOfBoundsException t) { + throw new EndOfInput(t); + } + } + /** * Transfers this buffer's data to a newly created byte array starting at the * current position and increases the position by the number of the