/* * Copyright (C) 2015 Actor LLC. <https://actor.im> */ package im.actor.runtime.bser; import java.io.IOException; // Disabling Bounds checks for speeding up calculations /*-[ #define J2OBJC_DISABLE_ARRAY_BOUND_CHECKS 1 ]-*/ public class DataInput { private byte[] data; private int offset; private int maxOffset; public DataInput(byte[] data) { if (data == null) { throw new IllegalArgumentException("data can't be null"); } this.data = data; this.offset = 0; this.maxOffset = data.length; } public DataInput(byte[] data, int offset, int len) { if (data == null) { throw new IllegalArgumentException("data can't be null"); } if (offset < 0) { throw new IllegalArgumentException("Offset can't be negative"); } if (len < 0) { throw new IllegalArgumentException("Length can't be negative"); } if (data.length < offset + len) { throw new IllegalArgumentException("Inconsistent lengths, total: " + data.length + ", offset: " + offset + ", len: " + len); } this.data = data; this.offset = offset; this.maxOffset = offset + len; } public byte[] getData() { return data; } public boolean isEOF() { return maxOffset <= offset; } public int getOffset() { return offset; } // public int getRemaining() { // return maxOffset - offset; // } // // public void skip(int size) throws IOException { // if (offset + size > maxOffset) { // throw new IOException(); // } // offset += size; // } public int readByte() throws IOException { if (offset == maxOffset) { throw new IOException(); } return data[offset++] & 0xFF; } public int readInt() throws IOException { if (offset + 4 > maxOffset) { throw new IOException(); } int res = (data[offset + 3] & 0xFF) + ((data[offset + 2] & 0xFF) << 8) + ((data[offset + 1] & 0xFF) << 16) + ((data[offset] & 0xFF) << 24); offset += 4; return res; } public long readLong() throws IOException { if (offset + 8 > maxOffset) { throw new IOException(); } long a1 = data[offset + 3] & 0xFF; long a2 = data[offset + 2] & 0xFF; long a3 = data[offset + 1] & 0xFF; long a4 = data[offset + 0] & 0xFF; long res1 = (a1) + (a2 << 8) + (a3 << 16) + (a4 << 24); offset += 4; long b1 = data[offset + 3] & 0xFF; long b2 = data[offset + 2] & 0xFF; long b3 = data[offset + 1] & 0xFF; long b4 = data[offset + 0] & 0xFF; long res2 = (b1) + (b2 << 8) + (b3 << 16) + (b4 << 24); offset += 4; return res2 + (res1 << 32); } public long readUInt() throws IOException { if (offset + 4 > maxOffset) { throw new IOException(); } long a1 = data[offset + 3] & 0xFF; long a2 = data[offset + 2] & 0xFF; long a3 = data[offset + 1] & 0xFF; long a4 = data[offset + 0] & 0xFF; offset += 4; return (a1) + (a2 << 8) + (a3 << 16) + (a4 << 24); } public byte[] readBytes(int count) throws IOException { if (count < 0) { throw new IOException("Count can't be negative"); } if (count > BserLimits.MAX_BLOCK_SIZE) { throw new IOException("Unable to read more than 1 MB"); } if (offset + count > maxOffset) { throw new IOException("Too many to read, max len: " + maxOffset + ", required len: " + (offset + count)); } byte[] res = new byte[count]; for (int i = 0; i < count; i++) { res[i] = data[offset++]; } return res; } public int readVarInt32() throws IOException { long varInt = readVarInt(); if (varInt > Integer.MAX_VALUE || varInt < Integer.MIN_VALUE) { throw new IOException("Too big VarInt32"); } return (int) varInt; } public long readVarInt() throws IOException { long value = 0; long i = 0; long b; do { if (offset == maxOffset) { throw new IOException(); } b = data[offset++] & 0xFF; if ((b & 0x80) != 0) { value |= (b & 0x7F) << i; i += 7; if (i > 70) { throw new IOException(); } } else { break; } } while (true); return value | (b << i); } public byte[] readProtoBytes() throws IOException { long len = readVarInt(); if (len < 0) { throw new IOException(); } if (len > BserLimits.MAX_BLOCK_SIZE) { throw new IOException(); } return readBytes((int) len); } public long[] readProtoLongs() throws IOException { long len = readVarInt(); if (len < 0) { throw new IOException(); } if (len > BserLimits.MAX_PROTO_REPEATED) { throw new IOException(); } long[] res = new long[(int) len]; for (int i = 0; i < res.length; i++) { res[i] = readLong(); } return res; } public String readProtoString() throws IOException { byte[] data = readProtoBytes(); return new String(data, "UTF-8"); } public boolean readProtoBool() throws IOException { return readByte() != 0; } }