summaryrefslogtreecommitdiff
path: root/libjava/java/io/ObjectInputStream.java
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/java/io/ObjectInputStream.java')
-rw-r--r--libjava/java/io/ObjectInputStream.java1467
1 files changed, 1467 insertions, 0 deletions
diff --git a/libjava/java/io/ObjectInputStream.java b/libjava/java/io/ObjectInputStream.java
new file mode 100644
index 00000000000..7855480acb3
--- /dev/null
+++ b/libjava/java/io/ObjectInputStream.java
@@ -0,0 +1,1467 @@
+/* ObjectInputStream.java -- Class used to read serialized objects
+ Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+As a special exception, if you link this library with other files to
+produce an executable, this library does not by itself cause the
+resulting executable to be covered by the GNU General Public License.
+This exception does not however invalidate any other reasons why the
+executable file might be covered by the GNU General Public License. */
+
+
+package java.io;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import gnu.java.io.ObjectIdentityWrapper;
+import gnu.java.lang.reflect.TypeSignature;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+
+
+public class ObjectInputStream extends InputStream
+ implements ObjectInput, ObjectStreamConstants
+{
+ /**
+ Creates a new <code>ObjectInputStream</code> that will do all of
+ its reading from <code>in</code>. This method also checks
+ the stream by reading the header information (stream magic number
+ and stream version).
+
+ @exception IOException Reading stream header from underlying
+ stream cannot be completed.
+
+ @exception StreamCorruptedException An invalid stream magic
+ number or stream version was read from the stream.
+
+ @see readStreamHeader ()
+ */
+ public ObjectInputStream (InputStream in)
+ throws IOException, StreamCorruptedException
+ {
+ this.resolveEnabled = false;
+ this.isDeserializing = false;
+ this.blockDataPosition = 0;
+ this.blockDataBytes = 0;
+ this.blockData = new byte[BUFFER_SIZE];
+ this.blockDataInput = new DataInputStream (this);
+ this.realInputStream = new DataInputStream (in);
+ this.nextOID = baseWireHandle;
+ this.objectLookupTable = new Hashtable ();
+ this.validators = new Vector ();
+ setBlockDataMode (true);
+ readStreamHeader ();
+ }
+
+
+ /**
+ Returns the next deserialized object read from the underlying stream.
+
+ This method can be overriden by a class by implementing
+ <code>private void readObject (ObjectInputStream)</code>.
+
+ If an exception is thrown from this method, the stream is left in
+ an undefined state.
+
+ @exception ClassNotFoundException The class that an object being
+ read in belongs to cannot be found.
+
+ @exception IOException Exception from underlying
+ <code>InputStream</code>.
+ */
+ public final Object readObject () throws ClassNotFoundException, IOException
+ {
+ if (this.useSubclassMethod)
+ return readObjectOverride ();
+
+ boolean was_deserializing;
+
+ Object ret_val;
+ was_deserializing = this.isDeserializing;
+
+ if (! was_deserializing)
+ setBlockDataMode (false);
+
+ this.isDeserializing = true;
+
+// DEBUG ("MARKER ");
+ byte marker = this.realInputStream.readByte ();
+
+ switch (marker)
+ {
+ case TC_BLOCKDATA:
+ case TC_BLOCKDATALONG:
+ readNextBlock (marker);
+ throw new BlockDataException (this.blockDataBytes);
+
+ case TC_NULL:
+ ret_val = null;
+ break;
+
+ case TC_REFERENCE:
+ {
+// DEBUG ("REFERENCE ");
+ Integer oid = new Integer (this.realInputStream.readInt ());
+ ret_val = ((ObjectIdentityWrapper)
+ this.objectLookupTable.get (oid)).object;
+ break;
+ }
+
+ case TC_CLASS:
+ {
+ ObjectStreamClass osc = (ObjectStreamClass)readObject ();
+ Class clazz = osc.forClass ();
+ assignNewHandle (clazz);
+ ret_val = clazz;
+ break;
+ }
+
+ case TC_CLASSDESC:
+ {
+// DEBUG ("CLASSDESC NAME ");
+ String name = this.realInputStream.readUTF ();
+// DEBUG ("UID ");
+ long uid = this.realInputStream.readLong ();
+// DEBUG ("FLAGS ");
+ byte flags = this.realInputStream.readByte ();
+// DEBUG ("FIELD COUNT ");
+ short field_count = this.realInputStream.readShort ();
+ ObjectStreamField[] fields = new ObjectStreamField[field_count];
+
+ ObjectStreamClass osc = new ObjectStreamClass (name, uid,
+ flags, fields);
+ assignNewHandle (osc);
+
+ for (int i=0; i < field_count; i++)
+ {
+// DEBUG ("TYPE CODE ");
+ char type_code = (char)this.realInputStream.readByte ();
+// DEBUG ("FIELD NAME ");
+ String field_name = this.realInputStream.readUTF ();
+ String class_name;
+
+ if (type_code == 'L' || type_code == '[')
+ class_name = (String)readObject ();
+ else
+ class_name = String.valueOf (type_code);
+
+ fields[i] =
+ new ObjectStreamField (field_name,
+ TypeSignature.getClassForEncoding
+ (class_name));
+ }
+
+ setBlockDataMode (true);
+ osc.setClass (resolveClass (osc));
+ setBlockDataMode (false);
+
+// DEBUG ("ENDBLOCKDATA ");
+ if (this.realInputStream.readByte () != TC_ENDBLOCKDATA)
+ throw new IOException ("Data annotated to class was not consumed.");
+
+ osc.setSuperclass ((ObjectStreamClass)readObject ());
+ ret_val = osc;
+ break;
+ }
+
+ case TC_STRING:
+ {
+// DEBUG ("STRING ");
+ String s = this.realInputStream.readUTF ();
+ ret_val = processResoultion (s, assignNewHandle (s));
+ break;
+ }
+
+ case TC_ARRAY:
+ {
+ ObjectStreamClass osc = (ObjectStreamClass)readObject ();
+ Class componenetType = osc.forClass ().getComponentType ();
+// DEBUG ("ARRAY LENGTH ");
+ int length = this.realInputStream.readInt ();
+ Object array = Array.newInstance (componenetType, length);
+ int handle = assignNewHandle (array);
+ readArrayElements (array, componenetType);
+ ret_val = processResoultion (array, handle);
+ break;
+ }
+
+ case TC_OBJECT:
+ {
+ ObjectStreamClass osc = (ObjectStreamClass)readObject ();
+ Class clazz = osc.forClass ();
+
+ if (!Serializable.class.isAssignableFrom (clazz))
+ throw new NotSerializableException (clazz + " is not Serializable, and thus cannot be deserialized.");
+
+ if (Externalizable.class.isAssignableFrom (clazz))
+ {
+ Externalizable obj = null;
+
+ try
+ {
+ obj = (Externalizable)clazz.newInstance ();
+ }
+ catch (InstantiationException e)
+ {
+ throw new ClassNotFoundException ("Instance of " + clazz
+ + " could not be created");
+ }
+ catch (IllegalAccessException e)
+ {
+ throw new ClassNotFoundException ("Instance of " + clazz
+ + " could not be created because class or zero-argument constructor is not accessible");
+ }
+ catch (NoSuchMethodError e)
+ {
+ throw new ClassNotFoundException ("Instance of " + clazz
+ + " could not be created because zero-argument constructor is not defined");
+ }
+
+ int handle = assignNewHandle (obj);
+
+ boolean read_from_blocks = ((osc.getFlags () & SC_BLOCK_DATA) != 0);
+
+ if (read_from_blocks)
+ setBlockDataMode (true);
+
+ obj.readExternal (this);
+
+ if (read_from_blocks)
+ setBlockDataMode (false);
+
+ ret_val = processResoultion (obj, handle);
+ break;
+ } // end if (Externalizable.class.isAssignableFrom (clazz))
+
+ // find the first non-serializable, non-abstract
+ // class in clazz's inheritance hierarchy
+ Class first_nonserial = clazz.getSuperclass ();
+ while (Serializable.class.isAssignableFrom (first_nonserial)
+ || Modifier.isAbstract (first_nonserial.getModifiers ()))
+ first_nonserial = first_nonserial.getSuperclass ();
+
+// DEBUGln ("Using " + first_nonserial
+// + " as starting point for constructing " + clazz);
+
+ Object obj = null;
+ obj = newObject (clazz, first_nonserial);
+
+ if (obj == null)
+ throw new ClassNotFoundException ("Instance of " + clazz +
+ " could not be created");
+
+ int handle = assignNewHandle (obj);
+ this.currentObject = obj;
+ ObjectStreamClass[] hierarchy =
+ ObjectStreamClass.getObjectStreamClasses (clazz);
+
+// DEBUGln ("Got class hierarchy of depth " + hierarchy.length);
+
+ boolean has_read;
+ for (int i=0; i < hierarchy.length; i++)
+ {
+ this.currentObjectStreamClass = hierarchy[i];
+
+// DEBUGln ("Reading fields of "
+// + this.currentObjectStreamClass.getName ());
+
+ has_read = true;
+
+ try
+ {
+ this.currentObjectStreamClass.forClass ().
+ getDeclaredMethod ("readObject", readObjectParams);
+ }
+ catch (NoSuchMethodException e)
+ {
+ has_read = false;
+ }
+
+ // XXX: should initialize fields in classes in the hierarchy
+ // that aren't in the stream
+ // should skip over classes in the stream that aren't in the
+ // real classes hierarchy
+ readFields (obj, this.currentObjectStreamClass.fields,
+ has_read, this.currentObjectStreamClass);
+
+ if (has_read)
+ {
+// DEBUG ("ENDBLOCKDATA? ");
+ if (this.realInputStream.readByte () != TC_ENDBLOCKDATA)
+ throw new IOException ("No end of block data seen for class with readObject (ObjectInputStream) method.");
+ }
+ }
+
+ this.currentObject = null;
+ this.currentObjectStreamClass = null;
+ ret_val = processResoultion (obj, handle);
+ break;
+ }
+
+ case TC_RESET:
+ clearHandles ();
+ ret_val = readObject ();
+ break;
+
+ case TC_EXCEPTION:
+ {
+ Exception e = (Exception)readObject ();
+ clearHandles ();
+ throw new WriteAbortedException ("Exception thrown during writing of stream", e);
+ }
+
+ default:
+ throw new IOException ("Unknown marker on stream");
+ }
+
+ this.isDeserializing = was_deserializing;
+
+ if (! was_deserializing)
+ {
+ setBlockDataMode (true);
+
+ if (validators.size () > 0)
+ invokeValidators ();
+ }
+
+ return ret_val;
+ }
+
+
+ /**
+ Reads the current objects non-transient, non-static fields from
+ the current class from the underlying output stream.
+
+ This method is intended to be called from within a object's
+ <code>private void readObject (ObjectInputStream)</code>
+ method.
+
+ @exception ClassNotFoundException The class that an object being
+ read in belongs to cannot be found.
+
+ @exception NotActiveException This method was called from a
+ context other than from the current object's and current class's
+ <code>private void readObject (ObjectInputStream)</code>
+ method.
+
+ @exception IOException Exception from underlying
+ <code>OutputStream</code>.
+ */
+ public void defaultReadObject ()
+ throws ClassNotFoundException, IOException, NotActiveException
+ {
+ if (this.currentObject == null || this.currentObjectStreamClass == null)
+ throw new NotActiveException ("defaultReadObject called by non-active class and/or object");
+
+ if (fieldsAlreadyRead)
+ throw new NotActiveException ("defaultReadObject called but fields already read from stream (by defaultReadObject or readFields)");
+
+ readFields (this.currentObject,
+ this.currentObjectStreamClass.fields,
+ false, this.currentObjectStreamClass);
+
+ fieldsAlreadyRead = true;
+ }
+
+
+ /**
+ Registers a <code>ObjectInputValidation</code> to be carried out
+ on the object graph currently being deserialized before it is
+ returned to the original caller of <code>readObject ()</code>.
+ The order of validation for multiple
+ <code>ObjectInputValidation</code>s can be controled using
+ <code>priority</code>. Validators with higher priorities are
+ called first.
+
+ @see java.io.ObjectInputValidation
+
+ @exception InvalidObjectException <code>validator</code> is
+ <code>null</code>
+
+ @exception NotActiveException an attempt was made to add a
+ validator outside of the <code>readObject</code> method of the
+ object currently being deserialized
+ */
+ public void registerValidation (ObjectInputValidation validator,
+ int priority)
+ throws InvalidObjectException, NotActiveException
+ {
+ if (this.currentObject == null || this.currentObjectStreamClass == null)
+ throw new NotActiveException ("registerValidation called by non-active class and/or object");
+
+ if (validator == null)
+ throw new InvalidObjectException ("attempt to add a null ObjectInputValidation object");
+
+ this.validators.addElement (new ValidatorAndPriority (validator,
+ priority));
+ }
+
+
+ /**
+ Called when a class is being deserialized. This is a hook to
+ allow subclasses to read in information written by the
+ <code>annotateClass (Class)</code> method of an
+ <code>ObjectOutputStream</code>.
+
+ This implementation looks up the active call stack for a
+ <code>ClassLoader</code>; if a <code>ClassLoader</code> is found,
+ it is used to load the class associated with <code>osc</code>,
+ otherwise, the default system <code>ClassLoader</code> is used.
+
+ @exception IOException Exception from underlying
+ <code>OutputStream</code>.
+
+ @see java.io.ObjectOutputStream#annotateClass (java.lang.Class)
+ */
+ protected Class resolveClass (ObjectStreamClass osc)
+ throws ClassNotFoundException, IOException
+ {
+// DEBUGln ("Resolving " + osc);
+
+ SecurityManager sm = System.getSecurityManager ();
+
+ if (sm == null)
+ sm = new SecurityManager () {};
+
+ ClassLoader cl = currentClassLoader (sm);
+
+ if (cl == null)
+ {
+// DEBUGln ("No class loader found");
+ return Class.forName (osc.getName ());
+ }
+ else
+ {
+// DEBUGln ("Using " + cl);
+ return cl.loadClass (osc.getName ());
+ }
+ }
+
+
+ /**
+ Allows subclasses to resolve objects that are read from the
+ stream with other objects to be returned in their place. This
+ method is called the first time each object is encountered.
+
+ This method must be enabled before it will be called in the
+ serialization process.
+
+ @exception IOException Exception from underlying
+ <code>OutputStream</code>.
+
+ @see enableResolveObject (boolean)
+ */
+ protected Object resolveObject (Object obj) throws IOException
+ {
+ return obj;
+ }
+
+
+ /**
+ If <code>enable</code> is <code>true</code> and this object is
+ trusted, then <code>resolveObject (Object)</code> will be called
+ in subsequent calls to <code>readObject (Object)</code>.
+ Otherwise, <code>resolveObject (Object)</code> will not be called.
+
+ @exception SecurityException This class is not trusted.
+ */
+ protected boolean enableResolveObject (boolean enable)
+ throws SecurityException
+ {
+ if (enable)
+ if (getClass ().getClassLoader () != null)
+ throw new SecurityException ("Untrusted ObjectInputStream subclass attempted to enable object resolution");
+
+ boolean old_val = this.resolveEnabled;
+ this.resolveEnabled = enable;
+ return old_val;
+ }
+
+
+ /**
+ Reads stream magic and stream version information from the
+ underlying stream.
+
+ @exception IOException Exception from underlying stream.
+
+ @exception StreamCorruptedException An invalid stream magic
+ number or stream version was read from the stream.
+ */
+ protected void readStreamHeader ()
+ throws IOException, StreamCorruptedException
+ {
+// DEBUG ("STREAM MAGIC ");
+ if (this.realInputStream.readShort () != STREAM_MAGIC)
+ throw new StreamCorruptedException ("Invalid stream magic number");
+
+// DEBUG ("STREAM VERSION ");
+ if (this.realInputStream.readShort () != STREAM_VERSION)
+ throw new StreamCorruptedException ("Invalid stream version number");
+ }
+
+
+ public int read () throws IOException
+ {
+ if (this.readDataFromBlock)
+ {
+ if (this.blockDataPosition >= this.blockDataBytes)
+ readNextBlock ();
+ return this.blockData[this.blockDataPosition++];
+ }
+ else
+ return this.realInputStream.read ();
+ }
+
+ public int read (byte data[], int offset, int length) throws IOException
+ {
+ if (this.readDataFromBlock)
+ {
+ if (this.blockDataPosition + length >= this.blockDataBytes)
+ readNextBlock ();
+
+ System.arraycopy (this.blockData, this.blockDataPosition,
+ data, offset, length);
+ return length;
+ }
+ else
+ return this.realInputStream.read (data, offset, length);
+ }
+
+ public int available () throws IOException
+ {
+ if (this.readDataFromBlock)
+ {
+ if (this.blockDataPosition >= this.blockDataBytes)
+ readNextBlock ();
+
+ return this.blockDataBytes - this.blockDataPosition;
+ }
+ else
+ return this.realInputStream.available ();
+ }
+
+ public void close () throws IOException
+ {
+ this.realInputStream.close ();
+ }
+
+ public boolean readBoolean () throws IOException
+ {
+ return this.dataInputStream.readBoolean ();
+ }
+
+ public byte readByte () throws IOException
+ {
+ return this.dataInputStream.readByte ();
+ }
+
+ public int readUnsignedByte () throws IOException
+ {
+ return this.dataInputStream.readUnsignedByte ();
+ }
+
+ public short readShort () throws IOException
+ {
+ return this.dataInputStream.readShort ();
+ }
+
+ public int readUnsignedShort () throws IOException
+ {
+ return this.dataInputStream.readUnsignedShort ();
+ }
+
+ public char readChar () throws IOException
+ {
+ return this.dataInputStream.readChar ();
+ }
+
+ public int readInt () throws IOException
+ {
+ return this.dataInputStream.readInt ();
+ }
+
+ public long readLong () throws IOException
+ {
+ return this.dataInputStream.readLong ();
+ }
+
+ public float readFloat () throws IOException
+ {
+ return this.dataInputStream.readFloat ();
+ }
+
+ public double readDouble () throws IOException
+ {
+ return this.dataInputStream.readDouble ();
+ }
+
+ public void readFully (byte data[]) throws IOException
+ {
+ this.dataInputStream.readFully (data);
+ }
+
+ public void readFully (byte data[], int offset, int size)
+ throws IOException
+ {
+ this.dataInputStream.readFully (data, offset, size);
+ }
+
+ public int skipBytes (int len) throws IOException
+ {
+ return this.dataInputStream.skipBytes (len);
+ }
+
+ /**
+ @deprecated
+ @see java.io.DataInputStream#readLine ()
+ */
+ public String readLine () throws IOException
+ {
+ return this.dataInputStream.readLine ();
+ }
+
+ public String readUTF () throws IOException
+ {
+ return this.dataInputStream.readUTF ();
+ }
+
+
+ /**
+ This class allows a class to specify exactly which fields should
+ be read, and what values should be read for these fields.
+
+ XXX: finish up comments
+ */
+ public static abstract class GetField
+ {
+ public abstract ObjectStreamClass getObjectStreamClass ();
+
+ public abstract boolean defaulted (String name)
+ throws IOException, IllegalArgumentException;
+
+ public abstract boolean get (String name, boolean defvalue)
+ throws IOException, IllegalArgumentException;
+
+ public abstract char get (String name, char defvalue)
+ throws IOException, IllegalArgumentException;
+
+ public abstract byte get (String name, byte defvalue)
+ throws IOException, IllegalArgumentException;
+
+ public abstract short get (String name, short defvalue)
+ throws IOException, IllegalArgumentException;
+
+ public abstract int get (String name, int defvalue)
+ throws IOException, IllegalArgumentException;
+
+ public abstract long get (String name, long defvalue)
+ throws IOException, IllegalArgumentException;
+
+ public abstract float get (String name, float defvalue)
+ throws IOException, IllegalArgumentException;
+
+ public abstract double get (String name, double defvalue)
+ throws IOException, IllegalArgumentException;
+
+ public abstract Object get (String name, Object defvalue)
+ throws IOException, IllegalArgumentException;
+ }
+
+ public GetField readFields ()
+ throws IOException, ClassNotFoundException, NotActiveException
+ {
+ if (this.currentObject == null || this.currentObjectStreamClass == null)
+ throw new NotActiveException ("readFields called by non-active class and/or object");
+
+ if (fieldsAlreadyRead)
+ throw new NotActiveException ("readFields called but fields already read from stream (by defaultReadObject or readFields)");
+
+ final ObjectStreamClass clazz = this.currentObjectStreamClass;
+ final byte[] prim_field_data = new byte[clazz.primFieldSize];
+ final Object[] objs = new Object[clazz.objectFieldCount];
+ readFully (prim_field_data);
+ for (int i = 0; i < objs.length; ++ i)
+ objs[i] = readObject ();
+
+ return new GetField ()
+ {
+ public ObjectStreamClass getObjectStreamClass ()
+ {
+ return clazz;
+ }
+
+ public boolean defaulted (String name)
+ throws IOException, IllegalArgumentException
+ {
+ return clazz.getField (name) == null;
+ }
+
+ public boolean get (String name, boolean defvalue)
+ throws IOException, IllegalArgumentException
+ {
+ ObjectStreamField field = getField (name, Boolean.TYPE);
+
+ if (field == null)
+ return defvalue;
+
+ return prim_field_data[field.getOffset ()] == 0 ? false : true;
+ }
+
+ public char get (String name, char defvalue)
+ throws IOException, IllegalArgumentException
+ {
+ ObjectStreamField field = getField (name, Character.TYPE);
+
+ if (field == null)
+ return defvalue;
+
+ int off = field.getOffset ();
+
+ return (char)(((prim_field_data[off++] & 0xFF) << 8)
+ | (prim_field_data[off] & 0xFF));
+ }
+
+ public byte get (String name, byte defvalue)
+ throws IOException, IllegalArgumentException
+ {
+ ObjectStreamField field = getField (name, Byte.TYPE);
+
+ if (field == null)
+ return defvalue;
+
+ return prim_field_data[field.getOffset ()];
+ }
+
+ public short get (String name, short defvalue)
+ throws IOException, IllegalArgumentException
+ {
+ ObjectStreamField field = getField (name, Short.TYPE);
+
+ if (field == null)
+ return defvalue;
+
+ int off = field.getOffset ();
+
+ return (short)(((prim_field_data[off++] & 0xFF) << 8)
+ | (prim_field_data[off] & 0xFF));
+ }
+
+ public int get (String name, int defvalue)
+ throws IOException, IllegalArgumentException
+ {
+ ObjectStreamField field = getField (name, Integer.TYPE);
+
+ if (field == null)
+ return defvalue;
+
+ int off = field.getOffset ();
+
+ return ((prim_field_data[off++] & 0xFF) << 24)
+ | ((prim_field_data[off++] & 0xFF) << 16)
+ | ((prim_field_data[off++] & 0xFF) << 8)
+ | (prim_field_data[off] & 0xFF);
+ }
+
+ public long get (String name, long defvalue)
+ throws IOException, IllegalArgumentException
+ {
+ ObjectStreamField field = getField (name, Long.TYPE);
+
+ if (field == null)
+ return defvalue;
+
+ int off = field.getOffset ();
+
+ return (long)(((prim_field_data[off++] & 0xFF) << 56)
+ | ((prim_field_data[off++] & 0xFF) << 48)
+ | ((prim_field_data[off++] & 0xFF) << 40)
+ | ((prim_field_data[off++] & 0xFF) << 32)
+ | ((prim_field_data[off++] & 0xFF) << 24)
+ | ((prim_field_data[off++] & 0xFF) << 16)
+ | ((prim_field_data[off++] & 0xFF) << 8)
+ | (prim_field_data[off] & 0xFF));
+ }
+
+ public float get (String name, float defvalue)
+ throws IOException, IllegalArgumentException
+ {
+ ObjectStreamField field = getField (name, Float.TYPE);
+
+ if (field == null)
+ return defvalue;
+
+ int off = field.getOffset ();
+
+ return Float.intBitsToFloat (((prim_field_data[off++] & 0xFF) << 24)
+ | ((prim_field_data[off++] & 0xFF) << 16)
+ | ((prim_field_data[off++] & 0xFF) << 8)
+ | (prim_field_data[off] & 0xFF));
+ }
+
+ public double get (String name, double defvalue)
+ throws IOException, IllegalArgumentException
+ {
+ ObjectStreamField field = getField (name, Double.TYPE);
+
+ if (field == null)
+ return defvalue;
+
+ int off = field.getOffset ();
+
+ return Double.longBitsToDouble (
+ (long)(((prim_field_data[off++] & 0xFF) << 56)
+ | ((prim_field_data[off++] & 0xFF) << 48)
+ | ((prim_field_data[off++] & 0xFF) << 40)
+ | ((prim_field_data[off++] & 0xFF) << 32)
+ | ((prim_field_data[off++] & 0xFF) << 24)
+ | ((prim_field_data[off++] & 0xFF) << 16)
+ | ((prim_field_data[off++] & 0xFF) << 8)
+ | (prim_field_data[off] & 0xFF)));
+ }
+
+ public Object get (String name, Object defvalue)
+ throws IOException, IllegalArgumentException
+ {
+ ObjectStreamField field = getField (name, null);
+
+ if (field == null)
+ return defvalue;
+
+ return objs[field.getOffset ()];
+ }
+
+ private ObjectStreamField getField (String name, Class type)
+ throws IllegalArgumentException
+ {
+ ObjectStreamField field = clazz.getField (name);
+
+ if (field == null)
+ return null;
+
+ Class field_type = field.getType ();
+
+ if (type == field_type ||
+ (type != null && field_type.isPrimitive ()))
+ return field;
+
+ throw new IllegalArgumentException ("Field requested is of type "
+ + field_type.getName ()
+ + ", but requested type was "
+ + (type == null ?
+ "Object" : type.getName ()));
+ }
+ };
+
+ }
+
+
+ /**
+ Protected constructor that allows subclasses to override
+ deserialization. This constructor should be called by subclasses
+ that wish to override <code>readObject (Object)</code>. This
+ method does a security check <i>NOTE: currently not
+ implemented</i>, then sets a flag that informs
+ <code>readObject (Object)</code> to call the subclasses
+ <code>readObjectOverride (Object)</code> method.
+
+ @see readObjectOverride (Object)
+ */
+ protected ObjectInputStream ()
+ throws IOException, SecurityException
+ {
+ SecurityManager sec_man = System.getSecurityManager ();
+ if (sec_man != null)
+ sec_man.checkPermission (SUBCLASS_IMPLEMENTATION_PERMISSION);
+ this.useSubclassMethod = true;
+ }
+
+
+ /**
+ This method allows subclasses to override the default
+ de serialization mechanism provided by
+ <code>ObjectInputStream</code>. To make this method be used for
+ writing objects, subclasses must invoke the 0-argument
+ constructor on this class from there constructor.
+
+ @see ObjectInputStream ()
+ */
+ protected Object readObjectOverride ()
+ throws ClassNotFoundException, IOException, OptionalDataException
+ {
+ throw new IOException ("Subclass of ObjectInputStream must implement readObjectOverride");
+ }
+
+
+ // assigns the next availible handle to OBJ
+ private int assignNewHandle (Object obj)
+ {
+ this.objectLookupTable.put (new Integer (this.nextOID),
+ new ObjectIdentityWrapper (obj));
+
+// try
+// {
+// DEBUG ("Assigning handle " + this.nextOID);
+// DEBUGln (" to " + obj);
+// }
+// catch (Throwable t) {}
+
+ return this.nextOID++;
+ }
+
+
+ private Object processResoultion (Object obj, int handle)
+ throws IOException
+ {
+ if (obj instanceof Resolvable)
+ obj = ((Resolvable)obj).readResolve ();
+
+ if (this.resolveEnabled)
+ obj = resolveObject (obj);
+
+ this.objectLookupTable.put (new Integer (handle),
+ new ObjectIdentityWrapper (obj));
+
+ return obj;
+ }
+
+
+ private void clearHandles ()
+ {
+ this.objectLookupTable.clear ();
+ this.nextOID = baseWireHandle;
+ }
+
+
+ private void readNextBlock () throws IOException
+ {
+// DEBUG ("MARKER ");
+ readNextBlock (this.realInputStream.readByte ());
+ }
+
+
+ private void readNextBlock (byte marker) throws IOException
+ {
+ if (marker == TC_BLOCKDATA)
+ {
+// DEBUG ("BLOCK DATA SIZE ");
+ this.blockDataBytes = this.realInputStream.readUnsignedByte ();
+ }
+ else if (marker == TC_BLOCKDATALONG)
+ {
+// DEBUG ("BLOCK DATA LONG SIZE ");
+ this.blockDataBytes = this.realInputStream.readInt ();
+ }
+ else
+ {
+ throw new EOFException ("Attempt to read primitive data, but no data block is active.");
+ }
+
+ if (this.blockData.length < this.blockDataBytes)
+ this.blockData = new byte[this.blockDataBytes];
+
+ this.realInputStream.readFully (this.blockData, 0, this.blockDataBytes);
+ this.blockDataPosition = 0;
+ }
+
+
+ private void readArrayElements (Object array, Class clazz)
+ throws ClassNotFoundException, IOException
+ {
+ if (clazz.isPrimitive ())
+ {
+ if (clazz == Boolean.TYPE)
+ {
+ boolean[] cast_array = (boolean[])array;
+ for (int i=0; i < cast_array.length; i++)
+ cast_array[i] = this.realInputStream.readBoolean ();
+ return;
+ }
+ if (clazz == Byte.TYPE)
+ {
+ byte[] cast_array = (byte[])array;
+ for (int i=0; i < cast_array.length; i++)
+ cast_array[i] = this.realInputStream.readByte ();
+ return;
+ }
+ if (clazz == Character.TYPE)
+ {
+ char[] cast_array = (char[])array;
+ for (int i=0; i < cast_array.length; i++)
+ cast_array[i] = this.realInputStream.readChar ();
+ return;
+ }
+ if (clazz == Double.TYPE)
+ {
+ double[] cast_array = (double[])array;
+ for (int i=0; i < cast_array.length; i++)
+ cast_array[i] = this.realInputStream.readDouble ();
+ return;
+ }
+ if (clazz == Float.TYPE)
+ {
+ float[] cast_array = (float[])array;
+ for (int i=0; i < cast_array.length; i++)
+ cast_array[i] = this.realInputStream.readFloat ();
+ return;
+ }
+ if (clazz == Integer.TYPE)
+ {
+ int[] cast_array = (int[])array;
+ for (int i=0; i < cast_array.length; i++)
+ cast_array[i] = this.realInputStream.readInt ();
+ return;
+ }
+ if (clazz == Long.TYPE)
+ {
+ long[] cast_array = (long[])array;
+ for (int i=0; i < cast_array.length; i++)
+ cast_array[i] = this.realInputStream.readLong ();
+ return;
+ }
+ if (clazz == Short.TYPE)
+ {
+ short[] cast_array = (short[])array;
+ for (int i=0; i < cast_array.length; i++)
+ cast_array[i] = this.realInputStream.readShort ();
+ return;
+ }
+ }
+ else
+ {
+ Object[] cast_array = (Object[])array;
+ for (int i=0; i < cast_array.length; i++)
+ cast_array[i] = readObject ();
+ }
+ }
+
+
+ private void readFields (Object obj, ObjectStreamField[] stream_fields,
+ boolean call_read_method,
+ ObjectStreamClass stream_osc)
+ throws ClassNotFoundException, IOException
+ {
+ if (call_read_method)
+ {
+ fieldsAlreadyRead = false;
+ setBlockDataMode (true);
+ callReadMethod (obj, stream_osc.forClass ());
+ setBlockDataMode (false);
+ return;
+ }
+
+ ObjectStreamField[] real_fields =
+ ObjectStreamClass.lookup (stream_osc.forClass ()).fields;
+
+ boolean default_initialize, set_value;
+ String field_name = null;
+ Class type = null;
+ ObjectStreamField stream_field = null;
+ ObjectStreamField real_field = null;
+ int stream_idx = 0;
+ int real_idx = 0;
+
+ while (stream_idx < stream_fields.length
+ && real_idx < real_fields.length)
+ {
+ default_initialize = false;
+ set_value = true;
+
+ if (stream_idx == stream_fields.length)
+ default_initialize = true;
+ else
+ {
+ stream_field = stream_fields[stream_idx];
+ type = stream_field.getType ();
+ }
+
+ if (real_idx == real_fields.length)
+ set_value = false;
+ else
+ {
+ real_field = real_fields[real_idx];
+ type = real_field.getType ();
+ field_name = real_field.getName ();
+ }
+
+ if (set_value && !default_initialize)
+ {
+ int comp_val =
+ real_field.compareTo (stream_field);
+
+ if (comp_val < 0)
+ {
+ default_initialize = true;
+ real_idx++;
+ }
+ else if (comp_val > 0)
+ {
+ set_value = false;
+ stream_idx++;
+ }
+ else
+ {
+ real_idx++;
+ stream_idx++;
+ }
+ }
+
+ if (type == Boolean.TYPE)
+ {
+ boolean value =
+ default_initialize ? false : this.realInputStream.readBoolean ();
+ if (set_value)
+ setBooleanField (obj, field_name, value);
+ }
+ else if (type == Byte.TYPE)
+ {
+ byte value =
+ default_initialize ? 0 : this.realInputStream.readByte ();
+ if (set_value)
+ setByteField (obj, field_name, value);
+ }
+ else if (type == Character.TYPE)
+ {
+ char value =
+ default_initialize ? (char)0 : this.realInputStream.readChar ();
+ if (set_value)
+ setCharField (obj, field_name, value);
+ }
+ else if (type == Double.TYPE)
+ {
+ double value =
+ default_initialize ? 0 : this.realInputStream.readDouble ();
+ if (set_value)
+ setDoubleField (obj, field_name, value);
+ }
+ else if (type == Float.TYPE)
+ {
+ float value =
+ default_initialize ? 0 : this.realInputStream.readFloat ();
+ if (set_value)
+ setFloatField (obj, field_name, value);
+ }
+ else if (type == Integer.TYPE)
+ {
+ int value =
+ default_initialize ? 0 : this.realInputStream.readInt ();
+ if (set_value)
+ setIntField (obj, field_name, value);
+ }
+ else if (type == Long.TYPE)
+ {
+ long value =
+ default_initialize ? 0 : this.realInputStream.readLong ();
+ if (set_value)
+ setLongField (obj, field_name, value);
+ }
+ else if (type == Short.TYPE)
+ {
+ short value =
+ default_initialize ? (short)0 : this.realInputStream.readShort ();
+ if (set_value)
+ setShortField (obj, field_name, value);
+ }
+ else
+ {
+ Object value =
+ default_initialize ? null : readObject ();
+ if (set_value)
+ setObjectField (obj, field_name,
+ real_field.getTypeString (), value);
+ }
+ }
+ }
+
+
+ // Toggles writing primitive data to block-data buffer.
+ private void setBlockDataMode (boolean on)
+ {
+// DEBUGln ("Setting block data mode to " + on);
+
+ this.readDataFromBlock = on;
+
+ if (on)
+ this.dataInputStream = this.blockDataInput;
+ else
+ this.dataInputStream = this.realInputStream;
+ }
+
+
+ // returns a new instance of REAL_CLASS that has been constructed
+ // only to th level of CONSTRUCTOR_CLASS (a super class of REAL_CLASS)
+ private Object newObject (Class real_class, Class constructor_class)
+ {
+ try
+ {
+ Object obj = allocateObject (real_class);
+ callConstructor (constructor_class, obj);
+ return obj;
+ }
+ catch (InstantiationException e)
+ {
+ return null;
+ }
+ }
+
+
+ // runs all registered ObjectInputValidations in prioritized order
+ // on OBJ
+ private void invokeValidators () throws InvalidObjectException
+ {
+ Object[] validators = new Object[this.validators.size ()];
+ this.validators.copyInto (validators);
+ Arrays.sort (validators);
+
+ try
+ {
+ for (int i=0; i < validators.length; i++)
+ ((ObjectInputValidation)validators[i]).validateObject ();
+ }
+ finally
+ {
+ this.validators.removeAllElements ();
+ }
+ }
+
+
+ // this native method is used to get access to the protected method
+ // of the same name in SecurityManger
+ private static ClassLoader currentClassLoader (SecurityManager sm)
+ {
+ // FIXME: This is too simple.
+ return ClassLoader.getSystemClassLoader ();
+ }
+
+ private static native Field getField (Class klass, String name)
+ throws java.lang.NoSuchFieldException;
+
+ private static native Method getMethod (Class klass, String name, Class args[])
+ throws java.lang.NoSuchMethodException;
+
+ private void callReadMethod (Object obj, Class klass) throws IOException
+ {
+ try
+ {
+ Class classArgs[] = {Class.forName ("java.io.ObjectInputStream")};
+ Method m = getMethod (klass, "readObject", classArgs);
+ if (m == null)
+ return;
+ Object args[] = {this};
+ m.invoke (obj, args);
+ }
+ catch (Exception _)
+ {
+ throw new IOException ();
+ }
+ }
+
+ private native Object allocateObject (Class clazz)
+ throws InstantiationException;
+
+ private native void callConstructor (Class clazz, Object obj);
+
+ private void setBooleanField (Object obj, String field_name,
+ boolean val)
+ {
+ try
+ {
+ Class klass = obj.getClass ();
+ Field f = getField (klass, field_name);
+ f.setBoolean (obj, val);
+ }
+ catch (Exception _)
+ {
+ }
+ }
+
+ private void setByteField (Object obj, String field_name,
+ byte val)
+ {
+ try
+ {
+ Class klass = obj.getClass ();
+ Field f = getField (klass, field_name);
+ f.setByte (obj, val);
+ }
+ catch (Exception _)
+ {
+ }
+ }
+
+ private void setCharField (Object obj, String field_name,
+ char val)
+ {
+ try
+ {
+ Class klass = obj.getClass ();
+ Field f = getField (klass, field_name);
+ f.setChar (obj, val);
+ }
+ catch (Exception _)
+ {
+ }
+ }
+
+ private void setDoubleField (Object obj, String field_name,
+ double val)
+ {
+ try
+ {
+ Class klass = obj.getClass ();
+ Field f = getField (klass, field_name);
+ f.setDouble (obj, val);
+ }
+ catch (Exception _)
+ {
+ }
+ }
+
+ private void setFloatField (Object obj, String field_name,
+ float val)
+ {
+ try
+ {
+ Class klass = obj.getClass ();
+ Field f = getField (klass, field_name);
+ f.setFloat (obj, val);
+ }
+ catch (Exception _)
+ {
+ }
+ }
+
+ private void setIntField (Object obj, String field_name,
+ int val)
+ {
+ try
+ {
+ Class klass = obj.getClass ();
+ Field f = getField (klass, field_name);
+ f.setInt (obj, val);
+ }
+ catch (Exception _)
+ {
+ }
+ }
+
+
+ private void setLongField (Object obj, String field_name,
+ long val)
+ {
+ try
+ {
+ Class klass = obj.getClass ();
+ Field f = getField (klass, field_name);
+ f.setLong (obj, val);
+ }
+ catch (Exception _)
+ {
+ }
+ }
+
+
+ private void setShortField (Object obj, String field_name,
+ short val)
+ {
+ try
+ {
+ Class klass = obj.getClass ();
+ Field f = getField (klass, field_name);
+ f.setShort (obj, val);
+ }
+ catch (Exception _)
+ {
+ }
+ }
+
+
+ private void setObjectField (Object obj, String field_name, String type_code,
+ Object val)
+ {
+ try
+ {
+ Class klass = obj.getClass ();
+ Field f = getField (klass, field_name);
+ // FIXME: We should check the type_code here
+ f.set (obj, val);
+ }
+ catch (Exception _)
+ {
+ }
+ }
+
+ private static final int BUFFER_SIZE = 1024;
+ private static final Class[] readObjectParams = { ObjectInputStream.class };
+
+ private DataInputStream realInputStream;
+ private DataInputStream dataInputStream;
+ private DataInputStream blockDataInput;
+ private int blockDataPosition;
+ private int blockDataBytes;
+ private byte[] blockData;
+ private boolean useSubclassMethod;
+ private int nextOID;
+ private boolean resolveEnabled;
+ private Hashtable objectLookupTable;
+ private Object currentObject;
+ private ObjectStreamClass currentObjectStreamClass;
+ private boolean readDataFromBlock;
+ private boolean isDeserializing;
+ private boolean fieldsAlreadyRead;
+ private Vector validators;
+
+
+/* FIXME: These 2 methods cause a build error on i686-pc-linux-gnu.
+ private void DEBUG (String msg)
+ {
+ System.out.print (msg);
+ }
+
+
+ private void DEBUGln (String msg)
+ {
+ System.out.println (msg);
+ }
+* end FIXME */
+}
+
+
+// used to keep a prioritized list of object validators
+class ValidatorAndPriority implements Comparable
+{
+ int priority;
+ ObjectInputValidation validator;
+
+ ValidatorAndPriority (ObjectInputValidation validator, int priority)
+ {
+ this.priority = priority;
+ this.validator = validator;
+ }
+
+ public int compareTo (Object o)
+ {
+ ValidatorAndPriority vap = (ValidatorAndPriority)o;
+ return this.priority - vap.priority;
+ }
+}