2
* Copyright (c) 1995, 2006, Oracle and/or its affiliates. All rights reserved.
3
* Copyright 2009 Jeroen Frijters
4
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6
* This code is free software; you can redistribute it and/or modify it
7
* under the terms of the GNU General Public License version 2 only, as
8
* published by the Free Software Foundation. Oracle designates this
9
* particular file as subject to the "Classpath" exception as provided
10
* by Oracle in the LICENSE file that accompanied this code.
12
* This code is distributed in the hope that it will be useful, but WITHOUT
13
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15
* version 2 for more details (a copy is included in the LICENSE file that
16
* accompanied this code).
18
* You should have received a copy of the GNU General Public License version
19
* 2 along with this work; if not, write to the Free Software Foundation,
20
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
22
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23
* or visit www.oracle.com if you need additional information or have any
28
import cli.System.Runtime.Serialization.SerializationException;
29
import cli.System.Runtime.Serialization.SerializationInfo;
30
import java.util.concurrent.atomic.AtomicBoolean;
33
public final class InteropObjectInputStream extends ObjectInputStream
35
private ObjectDataInputStream dis;
36
private CallbackContext curContext;
38
public static void readObject(Object obj, SerializationInfo info)
42
new InteropObjectInputStream(obj, info);
46
ikvm.runtime.Util.throwException(new SerializationException(x.getMessage(), x));
50
private InteropObjectInputStream(Object obj, SerializationInfo info) throws IOException, ClassNotFoundException
52
dis = new ObjectDataInputStream(info);
53
if (obj instanceof ObjectStreamClass)
57
case TC_PROXYCLASSDESC:
58
readProxyDesc((ObjectStreamClass)obj);
61
readNonProxyDesc((ObjectStreamClass)obj);
64
throw new StreamCorruptedException();
69
readOrdinaryObject(obj);
73
private ObjectStreamClass readClassDesc() throws IOException, ClassNotFoundException
75
return (ObjectStreamClass)readObject();
78
private void readProxyDesc(ObjectStreamClass desc) throws IOException, ClassNotFoundException
80
int numIfaces = readInt();
81
Class[] ifaces = new Class[numIfaces];
82
for (int i = 0; i < numIfaces; i++)
84
ifaces[i] = (Class)readObject();
86
Class cl = java.lang.reflect.Proxy.getProxyClass(Thread.currentThread().getContextClassLoader(), ifaces);
87
desc.initProxy(cl, null, readClassDesc());
90
private void readNonProxyDesc(ObjectStreamClass desc) throws IOException, ClassNotFoundException
92
Class cl = (Class)readObject();
93
ObjectStreamClass readDesc = new ObjectStreamClass();
94
readDesc.readNonProxy(this);
95
desc.initNonProxy(readDesc, cl, null, readClassDesc());
98
private void readOrdinaryObject(Object obj) throws IOException, ClassNotFoundException
100
ObjectStreamClass desc = readClassDesc();
101
desc.checkDeserialize();
103
if (obj instanceof InteropObjectOutputStream.DynamicProxy)
105
InteropObjectOutputStream.DynamicProxy pp = (InteropObjectOutputStream.DynamicProxy)obj;
108
obj = desc.newInstance();
113
throw (IOException) new InvalidClassException(
114
desc.forClass().getName(),
115
"unable to create instance").initCause(ex);
119
if (desc.isExternalizable())
121
readExternalData((Externalizable)obj, desc);
125
readSerialData(obj, desc);
129
private void readExternalData(Externalizable obj, ObjectStreamClass desc) throws IOException, ClassNotFoundException
131
CallbackContext oldContext = curContext;
134
obj.readExternal(this);
137
curContext = oldContext;
141
private void readSerialData(Object obj, ObjectStreamClass desc) throws IOException, ClassNotFoundException
143
ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
144
for (int i = 0; i < slots.length; i++)
146
ObjectStreamClass slotDesc = slots[i].desc;
148
if (slots[i].hasData)
150
if (slotDesc.hasReadObjectMethod())
152
CallbackContext oldContext = curContext;
155
curContext = new CallbackContext(obj, slotDesc);
156
slotDesc.invokeReadObject(obj, this);
160
curContext.setUsed();
161
curContext = oldContext;
166
defaultReadFields(obj, slotDesc);
168
if (slotDesc.hasWriteObjectData())
173
else if (slotDesc.hasReadObjectNoDataMethod())
175
slotDesc.invokeReadObjectNoData(obj);
180
private void skipCustomData() throws IOException
185
private void defaultReadFields(Object obj, ObjectStreamClass desc) throws IOException, ClassNotFoundException
187
byte[] primVals = new byte[desc.getPrimDataSize()];
189
desc.setPrimFieldValues(obj, primVals);
191
Object[] objVals = new Object[desc.getNumObjFields()];
192
for (int i = 0; i < objVals.length; i++)
194
objVals[i] = readObject();
196
desc.setObjFieldValues(obj, objVals);
200
public void defaultReadObject() throws IOException, ClassNotFoundException
202
if (curContext == null) {
203
throw new NotActiveException("not in call to readObject");
205
Object curObj = curContext.getObj();
206
ObjectStreamClass curDesc = curContext.getDesc();
207
defaultReadFields(curObj, curDesc);
211
protected Object readObjectOverride() throws IOException
213
return dis.readObject();
217
public Object readUnshared()
219
throw new UnsupportedOperationException();
223
public ObjectInputStream.GetField readFields() throws IOException, ClassNotFoundException
225
if (curContext == null) {
226
throw new NotActiveException("not in call to readObject");
228
Object curObj = curContext.getObj();
229
ObjectStreamClass curDesc = curContext.getDesc();
230
GetFieldImpl getField = new GetFieldImpl(curDesc);
231
getField.readFields();
236
public void registerValidation(ObjectInputValidation obj, int prio)
238
throw new UnsupportedOperationException();
242
public int read() throws IOException
248
public int read(byte[] buf, int off, int len) throws IOException
250
return dis.read(buf, off, len);
254
public int available() throws IOException
256
return dis.available();
260
public void close() throws IOException
262
throw new UnsupportedOperationException();
266
public boolean readBoolean() throws IOException
268
return dis.readBoolean();
272
public byte readByte() throws IOException
274
return dis.readByte();
278
public int readUnsignedByte() throws IOException
280
return dis.readUnsignedByte();
284
public char readChar() throws IOException
286
return dis.readChar();
290
public short readShort() throws IOException
292
return dis.readShort();
296
public int readUnsignedShort() throws IOException
298
return dis.readUnsignedShort();
302
public int readInt() throws IOException
304
return dis.readInt();
308
public long readLong() throws IOException
310
return dis.readLong();
314
public float readFloat() throws IOException
316
return dis.readFloat();
320
public double readDouble() throws IOException
322
return dis.readDouble();
326
public void readFully(byte[] buf) throws IOException
328
readFully(buf, 0, buf.length);
332
public void readFully(byte[] buf, int off, int len) throws IOException
334
dis.readFully(buf, off, len);
338
public int skipBytes(int len) throws IOException
340
return dis.skipBytes(len);
345
public String readLine() throws IOException
347
return dis.readLine();
351
public String readUTF() throws IOException
353
return dis.readUTF();
356
// private API used by ObjectStreamClass
358
String readTypeString() throws IOException
360
return (String)readObjectOverride();
363
private final class GetFieldImpl extends GetField {
365
/** class descriptor describing serializable fields */
366
private final ObjectStreamClass desc;
367
/** primitive field values */
368
private final byte[] primVals;
369
/** object field values */
370
private final Object[] objVals;
371
/** object field value handles */
372
private final int[] objHandles;
375
* Creates GetFieldImpl object for reading fields defined in given
378
GetFieldImpl(ObjectStreamClass desc) {
380
primVals = new byte[desc.getPrimDataSize()];
381
objVals = new Object[desc.getNumObjFields()];
382
objHandles = new int[objVals.length];
385
public ObjectStreamClass getObjectStreamClass() {
389
public boolean defaulted(String name) throws IOException {
390
return (getFieldOffset(name, null) < 0);
393
public boolean get(String name, boolean val) throws IOException {
394
int off = getFieldOffset(name, Boolean.TYPE);
395
return (off >= 0) ? Bits.getBoolean(primVals, off) : val;
398
public byte get(String name, byte val) throws IOException {
399
int off = getFieldOffset(name, Byte.TYPE);
400
return (off >= 0) ? primVals[off] : val;
403
public char get(String name, char val) throws IOException {
404
int off = getFieldOffset(name, Character.TYPE);
405
return (off >= 0) ? Bits.getChar(primVals, off) : val;
408
public short get(String name, short val) throws IOException {
409
int off = getFieldOffset(name, Short.TYPE);
410
return (off >= 0) ? Bits.getShort(primVals, off) : val;
413
public int get(String name, int val) throws IOException {
414
int off = getFieldOffset(name, Integer.TYPE);
415
return (off >= 0) ? Bits.getInt(primVals, off) : val;
418
public float get(String name, float val) throws IOException {
419
int off = getFieldOffset(name, Float.TYPE);
420
return (off >= 0) ? Bits.getFloat(primVals, off) : val;
423
public long get(String name, long val) throws IOException {
424
int off = getFieldOffset(name, Long.TYPE);
425
return (off >= 0) ? Bits.getLong(primVals, off) : val;
428
public double get(String name, double val) throws IOException {
429
int off = getFieldOffset(name, Double.TYPE);
430
return (off >= 0) ? Bits.getDouble(primVals, off) : val;
433
public Object get(String name, Object val) throws IOException {
434
int off = getFieldOffset(name, Object.class);
443
* Reads primitive and object field values from stream.
445
void readFields() throws IOException {
446
readFully(primVals, 0, primVals.length);
448
for (int i = 0; i < objVals.length; i++) {
449
objVals[i] = readObjectOverride();
454
* Returns offset of field with given name and type. A specified type
455
* of null matches all types, Object.class matches all non-primitive
456
* types, and any other non-null type matches assignable types only.
457
* If no matching field is found in the (incoming) class
458
* descriptor but a matching field is present in the associated local
459
* class descriptor, returns -1. Throws IllegalArgumentException if
460
* neither incoming nor local class descriptor contains a match.
462
private int getFieldOffset(String name, Class type) {
463
ObjectStreamField field = desc.getField(name, type);
465
return field.getOffset();
466
} else if (desc.getLocalDesc().getField(name, type) != null) {
469
throw new IllegalArgumentException("no such field " + name +
470
" with type " + type);
475
private final static class CallbackContext {
476
private final Object obj;
477
private final ObjectStreamClass desc;
478
private final AtomicBoolean used = new AtomicBoolean();
480
public CallbackContext(Object obj, ObjectStreamClass desc) {
485
public Object getObj() throws NotActiveException {
490
public ObjectStreamClass getDesc() {
494
private void checkAndSetUsed() throws NotActiveException {
495
if (!used.compareAndSet(false, true)) {
496
throw new NotActiveException(
497
"not in readObject invocation or fields already read");
501
public void setUsed() {
506
private static final class ObjectDataInputStream extends DataInputStream
508
private final static class Inp extends FilterInputStream
510
private static final byte MARKER = 0;
511
private static final byte OBJECTS = 10;
512
private static final byte BYTES = 20;
513
private final SerializationInfo info;
516
private int blockEnd = -1;
517
private int objCount;
520
Inp(SerializationInfo info) throws IOException
524
buf = (byte[])info.GetValue("$data", ikvm.runtime.Util.getInstanceTypeFromClass(cli.System.Object.class));
528
private void modeSwitch() throws IOException
530
if (pos == buf.length)
532
// next read will report error
536
else if (buf[pos] == OBJECTS)
539
objCount = readPacked();
542
else if (buf[pos] == BYTES)
547
else if (buf[pos] == MARKER)
552
throw new StreamCorruptedException();
556
private int packedLength(int val)
560
// we only use packed integers for lengths or counts, so they can never be negative
567
else if (val < 16129)
577
private int readPacked()
579
int b1 = buf[pos++] & 0xFF;
586
return ((b1 & 127) << 7) + (buf[pos++] & 0xFF);
591
v |= (buf[pos++] & 0xFF) << 24;
592
v |= (buf[pos++] & 0xFF) << 16;
593
v |= (buf[pos++] & 0xFF) << 8;
594
v |= (buf[pos++] & 0xFF) << 0;
599
private void switchToData() throws IOException
601
if (blockEnd != -1 || objCount != 0 || buf[pos] == MARKER)
603
throw new StreamCorruptedException();
605
int len = readPacked();
606
blockEnd = pos + len;
607
if (blockEnd > buf.length)
609
throw new StreamCorruptedException();
613
public int read() throws IOException
615
if (blockEnd - pos < 1)
619
return buf[pos++] & 0xFF;
622
public int read(byte b[], int off, int len) throws IOException
628
if (blockEnd - pos < len)
632
System.arraycopy(buf, pos, b, off, len);
637
public long skip(long n) throws IOException
643
if (blockEnd - pos < n)
651
public int available() throws IOException
656
public void close() throws IOException
660
public void mark(int readlimit)
664
public void reset() throws IOException
668
public boolean markSupported()
673
Object readObject() throws IOException
677
if (pos != blockEnd || buf[pos] == MARKER)
679
throw new StreamCorruptedException();
682
objCount = readPacked();
685
return info.GetValue("$" + (objId++), ikvm.runtime.Util.getInstanceTypeFromClass(cli.System.Object.class));
688
void skipMarker() throws IOException
696
if (buf[pos] == MARKER)
709
if (pos == buf.length)
711
throw new StreamCorruptedException();
713
if (buf[pos] == MARKER)
720
objCount = readPacked();
725
ObjectDataInputStream(SerializationInfo info) throws IOException
727
super(new Inp(info));
730
public Object readObject() throws IOException
732
return ((Inp)in).readObject();
735
public void skipMarker() throws IOException
737
((Inp)in).skipMarker();