corda/classpath/java/io/ObjectInputStream.java
Johannes Schindelin 4b8285e597 Implement a rudimentary Java-compatible ObjectInputStream
The Java Language Specification documents the serialization protocol
implemented by this change set:

http://docs.oracle.com/javase/7/docs/platform/serialization/spec/protocol.html#10258

This change is intended to make it easier to use Avian VM as a drop-in
replacement for the Oracle JVM when serializing objects.

The previous serialization code is still available as
avian.LegacyObjectInputStream.

This commit only implements the non-object parts of the deserialization
specification.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2013-11-06 09:10:51 -06:00

227 lines
6.1 KiB
Java

/* Copyright (c) 2008-2013, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
import static java.io.ObjectOutputStream.STREAM_MAGIC;
import static java.io.ObjectOutputStream.STREAM_VERSION;
import static java.io.ObjectOutputStream.TC_NULL;
import static java.io.ObjectOutputStream.TC_REFERENCE;
import static java.io.ObjectOutputStream.TC_CLASSDESC;
import static java.io.ObjectOutputStream.TC_OBJECT;
import static java.io.ObjectOutputStream.TC_STRING;
import static java.io.ObjectOutputStream.TC_ARRAY;
import static java.io.ObjectOutputStream.TC_CLASS;
import static java.io.ObjectOutputStream.TC_BLOCKDATA;
import static java.io.ObjectOutputStream.TC_ENDBLOCKDATA;
import static java.io.ObjectOutputStream.TC_RESET;
import static java.io.ObjectOutputStream.TC_BLOCKDATALONG;
import static java.io.ObjectOutputStream.TC_EXCEPTION;
import static java.io.ObjectOutputStream.TC_LONGSTRING;
import static java.io.ObjectOutputStream.TC_PROXYCLASSDESC;
import static java.io.ObjectOutputStream.TC_ENUM;
import static java.io.ObjectOutputStream.SC_WRITE_METHOD;
import static java.io.ObjectOutputStream.SC_BLOCK_DATA;
import static java.io.ObjectOutputStream.SC_SERIALIZABLE;
import static java.io.ObjectOutputStream.SC_EXTERNALIZABLE;
import static java.io.ObjectOutputStream.SC_ENUM;
import avian.VMClass;
import java.util.HashMap;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class ObjectInputStream extends InputStream implements DataInput {
private final InputStream in;
public ObjectInputStream(InputStream in) throws IOException {
this.in = in;
short signature = (short)rawShort();
if (signature != STREAM_MAGIC) {
throw new IOException("Unrecognized signature: 0x"
+ Integer.toHexString(signature));
}
int version = rawShort();
if (version != STREAM_VERSION) {
throw new IOException("Unsupported version: " + version);
}
}
public int read() throws IOException {
return in.read();
}
private int rawByte() throws IOException {
int c = read();
if (c < 0) {
throw new EOFException();
}
return c;
}
private int rawShort() throws IOException {
return (rawByte() << 8) | rawByte();
}
private int rawInt() throws IOException {
return (rawShort() << 16) | rawShort();
}
private long rawLong() throws IOException {
return ((rawInt() & 0xffffffffl) << 32) | rawInt();
}
private String rawString() throws IOException {
int length = rawShort();
byte[] array = new byte[length];
readFully(array);
return new String(array);
}
public int read(byte[] b, int offset, int length) throws IOException {
return in.read(b, offset, length);
}
public void readFully(byte[] b) throws IOException {
readFully(b, 0, b.length);
}
public void readFully(byte[] b, int offset, int length) throws IOException {
while (length > 0) {
int count = read(b, offset, length);
if (count < 0) {
throw new EOFException("Reached EOF " + length + " bytes too early");
}
offset += count;
length -= count;
}
}
public String readLine() throws IOException {
int c = read();
if (c < 0) {
return null;
} else if (c == '\n') {
return "";
}
StringBuilder builder = new StringBuilder();
for (;;) {
builder.append((char)c);
c = read();
if (c < 0 || c == '\n') {
return builder.toString();
}
}
}
public void close() throws IOException {
in.close();
}
public Object readObject() throws IOException, ClassNotFoundException {
throw new UnsupportedOperationException();
}
private int remainingBlockData;
private int rawBlockDataByte() throws IOException {
while (remainingBlockData <= 0) {
int b = rawByte();
if (b == TC_BLOCKDATA) {
remainingBlockData = rawByte();
} else {
throw new UnsupportedOperationException("Unknown token: 0x"
+ Integer.toHexString(b));
}
}
--remainingBlockData;
return rawByte();
}
private int rawBlockDataShort() throws IOException {
return (rawBlockDataByte() << 8) | rawBlockDataByte();
}
private int rawBlockDataInt() throws IOException {
return (rawBlockDataShort() << 16) | rawBlockDataShort();
}
private long rawBlockDataLong() throws IOException {
return ((rawBlockDataInt() & 0xffffffffl) << 32) | rawBlockDataInt();
}
public boolean readBoolean() throws IOException {
return rawBlockDataByte() != 0;
}
public byte readByte() throws IOException {
return (byte)rawBlockDataByte();
}
public char readChar() throws IOException {
return (char)rawBlockDataShort();
}
public short readShort() throws IOException {
return (short)rawBlockDataShort();
}
public int readInt() throws IOException {
return rawBlockDataInt();
}
public long readLong() throws IOException {
return rawBlockDataLong();
}
public float readFloat() throws IOException {
return Float.intBitsToFloat(rawBlockDataInt());
}
public double readDouble() throws IOException {
return Double.longBitsToDouble(rawBlockDataLong());
}
public int readUnsignedByte() throws IOException {
return rawBlockDataByte();
}
public int readUnsignedShort() throws IOException {
return rawBlockDataShort();
}
public String readUTF() throws IOException {
int length = rawBlockDataShort();
if (remainingBlockData < length) {
throw new IOException("Short block data: "
+ remainingBlockData + " < " + length);
}
byte[] bytes = new byte[length];
readFully(bytes);
remainingBlockData -= length;
return new String(bytes, "UTF-8");
}
public int skipBytes(int count) throws IOException {
int i = 0;
while (i < count) {
if (read() < 0) {
return i;
}
++i;
}
return count;
}
private static native Object makeInstance(VMClass c);
}