package org.infinispan.marshall.core; import java.io.EOFException; import java.io.IOException; import java.io.ObjectInput; /** * Array backed {@link ObjectInput} implementation. * * {@link #skip(long)} and {@link #skipBytes(int)} have been enhanced so that * if a negative number is passed in, they skip backwards effectively * providing rewind capabilities. */ final class BytesObjectInput implements ObjectInput { final byte bytes[]; final GlobalMarshaller marshaller; int pos; int offset; // needed for external JBoss Marshalling, to be able to rewind correctly when the bytes are prepended :( private BytesObjectInput(byte[] bytes, int offset, GlobalMarshaller marshaller) { this.bytes = bytes; this.pos = offset; this.offset = offset; this.marshaller = marshaller; } static BytesObjectInput from(byte[] bytes, GlobalMarshaller marshaller) { return from(bytes, 0, marshaller); } static BytesObjectInput from(byte[] bytes, int offset, GlobalMarshaller marshaller) { return new BytesObjectInput(bytes, offset, marshaller); } @Override public Object readObject() throws ClassNotFoundException, IOException { return marshaller.readNullableObject(this); } @Override public int read() { if (pos >= bytes.length) { return -1; } return bytes[pos++] & 0xff; } @Override public int read(byte[] b) { return read(b, 0, b.length); } @Override public int read(byte[] b, int off, int len) { if (pos >= bytes.length) { return -1; } if (pos + len >= bytes.length) { len = bytes.length - pos; } System.arraycopy(bytes, pos, b, off, len); pos += len; return len; } @Override public long skip(long n) { if (n > 0) { long skip = bytes.length - pos; if (skip > n) skip = n; pos += skip; return skip; } else { int idx = Math.min(bytes.length, pos); long skip = idx + n; // Calculate max to avoid skipping before offset pos = (int) Math.max(skip, offset); return skip; } } @Override public int available() { return bytes.length - pos; } @Override public void close() { // No-op } @Override public void readFully(byte[] b) { readFully(b, 0, b.length); } @Override public void readFully(byte[] b, int off, int len) { System.arraycopy(bytes, pos, b, off, len); pos += len; } @Override public int skipBytes(int n) { return (int) skip(n); } @Override public boolean readBoolean() throws EOFException { return readByte() != 0; } @Override public byte readByte() throws EOFException { if (pos >= bytes.length) { throw new EOFException(); } return bytes[pos++]; } @Override public int readUnsignedByte() throws EOFException { return readByte() & 0xff; } @Override public short readShort() { short v = (short) (bytes[pos] << 8 | (bytes[pos + 1] & 0xff)); pos += 2; return v; } @Override public int readUnsignedShort() { int v = (bytes[pos] & 0xff) << 8 | (bytes[pos + 1] & 0xff); pos += 2; return v; } @Override public char readChar() { char v = (char) (bytes[pos] << 8 | (bytes[pos + 1] & 0xff)); pos += 2; return v; } @Override public int readInt() { int v = bytes[pos] << 24 | (bytes[pos + 1] & 0xff) << 16 | (bytes[pos + 2] & 0xff) << 8 | (bytes[pos + 3] & 0xff); pos = pos + 4; return v; } @Override public long readLong() { return (long) readInt() << 32L | (long) readInt() & 0xffffffffL; } @Override public float readFloat() { return Float.intBitsToFloat(readInt()); } @Override public double readDouble() { return Double.longBitsToDouble(readLong()); } @Override public String readLine() { return null; } @Override public String readUTF() { int utflen = readInt(); byte[] bytearr = bytes; char[] chararr = new char[utflen]; utflen = pos + utflen; int c, char2, char3; int count = pos; int chararr_count=0; while (count < utflen) { c = (int) bytearr[count] & 0xff; if (c > 127) break; count++; chararr[chararr_count++]=(char)c; } while (count < utflen) { c = (int) bytearr[count] & 0xff; switch (c >> 4) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: /* 0xxxxxxx*/ count++; chararr[chararr_count++]=(char)c; break; case 12: case 13: /* 110x xxxx 10xx xxxx*/ count += 2; if (count > utflen) throw new RuntimeException( "malformed input: partial character at end"); char2 = (int) bytearr[count-1]; if ((char2 & 0xC0) != 0x80) throw new RuntimeException( "malformed input around byte " + count); chararr[chararr_count++]=(char)(((c & 0x1F) << 6) | (char2 & 0x3F)); break; case 14: /* 1110 xxxx 10xx xxxx 10xx xxxx */ count += 3; if (count > utflen) throw new RuntimeException( "malformed input: partial character at end"); char2 = (int) bytearr[count-2]; char3 = (int) bytearr[count-1]; if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80)) throw new RuntimeException( "malformed input around byte " + (count-1)); chararr[chararr_count++]=(char)(((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | (char3 & 0x3F)); break; default: /* 10xx xxxx, 1111 xxxx */ throw new RuntimeException( "malformed input around byte " + count); } } pos = count; return new String(chararr, 0, chararr_count); } String readString() throws EOFException { int mark = readByte(); switch(mark) { case 0: return ""; // empty string case 1: // small ascii int size = readByte(); String str = new String(bytes, 0, pos, size); pos += size; return str; case 2: // large string return readUTF(); default: throw new RuntimeException("Unknown marker(String). mark=" + mark); } } }