aboutsummaryrefslogtreecommitdiff
path: root/libjava/java/io
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/java/io')
-rw-r--r--libjava/java/io/BlockDataException.java39
-rw-r--r--libjava/java/io/Externalizable.java98
-rw-r--r--libjava/java/io/InvalidClassException.java110
-rw-r--r--libjava/java/io/InvalidObjectException.java57
-rw-r--r--libjava/java/io/NotActiveException.java68
-rw-r--r--libjava/java/io/NotSerializableException.java69
-rw-r--r--libjava/java/io/ObjectInput.java147
-rw-r--r--libjava/java/io/ObjectInputStream.java1467
-rw-r--r--libjava/java/io/ObjectInputValidation.java50
-rw-r--r--libjava/java/io/ObjectOutput.java116
-rw-r--r--libjava/java/io/ObjectOutputStream.java1335
-rw-r--r--libjava/java/io/ObjectStreamClass.java666
-rw-r--r--libjava/java/io/ObjectStreamConstants.java74
-rw-r--r--libjava/java/io/ObjectStreamField.java99
-rw-r--r--libjava/java/io/Replaceable.java54
-rw-r--r--libjava/java/io/Resolvable.java52
-rw-r--r--libjava/java/io/SerializablePermission.java106
-rw-r--r--libjava/java/io/WriteAbortedException.java89
-rw-r--r--libjava/java/io/natObjectInputStream.cc78
-rw-r--r--libjava/java/io/natObjectOutputStream.cc33
20 files changed, 4807 insertions, 0 deletions
diff --git a/libjava/java/io/BlockDataException.java b/libjava/java/io/BlockDataException.java
new file mode 100644
index 0000000..ef70f54
--- /dev/null
+++ b/libjava/java/io/BlockDataException.java
@@ -0,0 +1,39 @@
+/* BlockDataException.java -- Class used to store name and class of fields
+ Copyright (C) 1998 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;
+
+//TODO: check 1.2 API to make sure this mathces
+
+class BlockDataException extends IOException
+{
+ public BlockDataException( int bytes )
+ {
+ super( bytes + " bytes are available in the next data block" );
+ }
+}
+
diff --git a/libjava/java/io/Externalizable.java b/libjava/java/io/Externalizable.java
new file mode 100644
index 0000000..045df86
--- /dev/null
+++ b/libjava/java/io/Externalizable.java
@@ -0,0 +1,98 @@
+/* Externalizable.java -- Interface for saving and restoring object data
+ Copyright (C) 1998 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;
+
+/**
+ * This interface provides a way that classes can completely control how
+ * the data of their object instances are written and read to and from
+ * streams. It has two methods which are used to write the data to a stream
+ * and to read the data from a stream. The read method must read the data
+ * in exactly the way it was written by the write method.
+ * <p>
+ * Note that classes which implement this interface must take into account
+ * that all superclass data must also be written to the stream as well.
+ * The class implementing this interface must figure out how to make that
+ * happen.
+ * <p>
+ * This interface can be used to provide object persistence. When an
+ * object is to be stored externally, the <code>writeExternal</code> method is
+ * called to save state. When the object is restored, an instance is
+ * created using the default no-argument constructor and the
+ * <code>readExternal</code> method is used to restore the state.
+ *
+ * @version 0.0
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public abstract interface Externalizable extends Serializable
+{
+
+/**
+ * This method restores an object's state by reading in the instance data
+ * for the object from the passed in stream. Note that this stream is not
+ * a subclass of <code>InputStream</code>, but rather is a class that implements
+ * the <code>ObjectInput</code> interface. That interface provides a mechanism for
+ * reading in Java data types from a stream.
+ * <p>
+ * Note that this method must be compatible with <code>writeExternal</code>.
+ * It must read back the exact same types that were written by that
+ * method in the exact order they were written.
+ * <p>
+ * If this method needs to read back an object instance, then the class
+ * for that object must be found and loaded. If that operation fails,
+ * then this method throws a <code>ClassNotFoundException</code>
+ *
+ * @param in An <code>ObjectInput</code> instance for reading in the object state
+ *
+ * @exception ClassNotFoundException If the class of an object being restored cannot be found
+ * @exception IOException If any other error occurs
+ */
+public abstract void
+readExternal(ObjectInput in) throws ClassNotFoundException, IOException;
+
+/*************************************************************************/
+
+/**
+ * This method is responsible for writing the instance data of an object
+ * to the passed in stream. Note that this stream is not a subclass of
+ * <code>OutputStream</code>, but rather is a class that implements the
+ * <code>ObjectOutput</code> interface. That interface provides a number of methods
+ * for writing Java data values to a stream.
+ * <p>
+ * Not that the implementation of this method must be coordinated with
+ * the implementation of <code>readExternal</code>.
+ *
+ * @param out An <code>ObjectOutput</code> instance for writing the object state
+ *
+ * @exception IOException If an error occurs
+ */
+public abstract void
+writeExternal(ObjectOutput out) throws IOException;
+
+} // interface Externalizable
+
diff --git a/libjava/java/io/InvalidClassException.java b/libjava/java/io/InvalidClassException.java
new file mode 100644
index 0000000..fd03154
--- /dev/null
+++ b/libjava/java/io/InvalidClassException.java
@@ -0,0 +1,110 @@
+/* InvalidClassException.java -- An I/O operation was interrupted.
+ Copyright (C) 1998 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;
+
+/**
+ * This exception is thrown when there is some sort of problem with a
+ * class during a serialization operation. This could be that the
+ * versions don't match, that there are unknown datatypes in the class
+ * or that the class doesn't have a default no-arg constructor.
+ * <p>
+ * The field <code>classname</code> will contain the name of the
+ * class that caused the problem if known. The getMessage() method
+ * for this exception will always include the name of that class
+ * if known.
+ *
+ * @version 0.0
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class InvalidClassException extends ObjectStreamException
+{
+
+/*
+ * Instance Variables
+ */
+
+/**
+ * The name of the class which encountered the error.
+ */
+public String classname;
+
+/*************************************************************************/
+
+/*
+ * Constructors
+ */
+
+/**
+ * Create a new InvalidClassException with a descriptive error message String
+ *
+ * @param message The descriptive error message
+ */
+public
+InvalidClassException(String message)
+{
+ super(message);
+}
+
+/*************************************************************************/
+
+/**
+ * Create a new InvalidClassException with a descriptive error message
+ * String, and the name of the class that caused the problem.
+ *
+ * @param classname The number of bytes tranferred before the interruption
+ * @param message The descriptive error message
+ */
+public
+InvalidClassException(String classname, String message)
+{
+ super(message);
+ this.classname = classname;
+}
+
+/*************************************************************************/
+
+/*
+ * Instance Methods
+ */
+
+/**
+ * Returns the descriptive error message for this exception. It will
+ * include the class name that caused the problem if known. This method
+ * overrides Throwable.getMessage()
+ *
+ * @return A descriptive error message
+ */
+public String
+getMessage()
+{
+ return(super.getMessage() + ": " + classname);
+}
+
+} // class InvalidClassException
+
diff --git a/libjava/java/io/InvalidObjectException.java b/libjava/java/io/InvalidObjectException.java
new file mode 100644
index 0000000..705082a
--- /dev/null
+++ b/libjava/java/io/InvalidObjectException.java
@@ -0,0 +1,57 @@
+/* InvalidObjectException.java -- An I/O operation was interrupted.
+ Copyright (C) 1998 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;
+
+/**
+ * This exception is thrown when an object fails a validation test
+ * during serialization.
+ *
+ * @version 0.0
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class InvalidObjectException extends ObjectStreamException
+{
+
+/*
+ * Constructors
+ */
+
+/**
+ * Create a new InvalidObjectException with a descriptive error message String
+ *
+ * @param message The descriptive error message
+ */
+public
+InvalidObjectException(String message)
+{
+ super(message);
+}
+
+} // class InvalidObjectException
+
diff --git a/libjava/java/io/NotActiveException.java b/libjava/java/io/NotActiveException.java
new file mode 100644
index 0000000..f628a3b
--- /dev/null
+++ b/libjava/java/io/NotActiveException.java
@@ -0,0 +1,68 @@
+/* NotActiveException.java -- Unexpected end of file exception
+ Copyright (C) 1998 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;
+
+/**
+ * This exception is thrown when a problem occurs due to the fact that
+ * serialization is not active.
+ *
+ * @version 0.0
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class NotActiveException extends ObjectStreamException
+{
+
+/*
+ * Constructors
+ */
+
+/**
+ * Create a new NotActiveException without a descriptive error message
+ */
+public
+NotActiveException()
+{
+ super();
+}
+
+/*************************************************************************/
+
+/**
+ * Create a new NotActiveException with a descriptive error message String
+ *
+ * @param message The descriptive error message
+ */
+public
+NotActiveException(String message)
+{
+ super(message);
+}
+
+} // class NotActiveException
+
diff --git a/libjava/java/io/NotSerializableException.java b/libjava/java/io/NotSerializableException.java
new file mode 100644
index 0000000..d1e0bd2
--- /dev/null
+++ b/libjava/java/io/NotSerializableException.java
@@ -0,0 +1,69 @@
+/* NotSerializableException.java -- Unexpected end of file exception
+ Copyright (C) 1998 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;
+
+/**
+ * This exception is thrown when a class may not be serialized. The
+ * descriptive message will consist of the name of the class in question.
+ *
+ * @version 0.0
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class NotSerializableException extends ObjectStreamException
+{
+
+/*
+ * Constructors
+ */
+
+/**
+ * Create a new NotSerializableException without a descriptive error message
+ */
+public
+NotSerializableException()
+{
+ super();
+}
+
+/*************************************************************************/
+
+/**
+ * Create a new NotSerializableException with a descriptive error message String
+ * This should be the name of the class that cannot be serialized.
+ *
+ * @param message The descriptive error message
+ */
+public
+NotSerializableException(String message)
+{
+ super(message);
+}
+
+} // class NotSerializableException
+
diff --git a/libjava/java/io/ObjectInput.java b/libjava/java/io/ObjectInput.java
new file mode 100644
index 0000000..ef23fa9
--- /dev/null
+++ b/libjava/java/io/ObjectInput.java
@@ -0,0 +1,147 @@
+/* ObjectInput.java -- Read object data from a stream
+ Copyright (C) 1998 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;
+
+/**
+ * This interface extends the <code>DataInput</code> interface to provide a
+ * facility to read objects as well as primitive types from a stream. It
+ * also has methods that allow input to be done in a manner similar to
+ * <code>InputStream</code>
+ *
+ * @version 0.0
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public abstract interface ObjectInput extends DataInput
+{
+
+/**
+ * This method returns the number of bytes that can be read without
+ * blocking.
+ *
+ * @return The number of bytes available before blocking
+ *
+ * @exception IOException If an error occurs
+ */
+public abstract int
+available() throws IOException;
+
+/*************************************************************************/
+
+/**
+ * This method reading a byte of data from a stream. It returns that byte
+ * as an int. This method blocks if no data is available to be read.
+ *
+ * @return The byte of data read
+ *
+ * @exception IOException If an error occurs
+ */
+public abstract int
+read() throws IOException;
+
+/*************************************************************************/
+
+/**
+ * This method reads raw bytes and stores them them a byte array buffer.
+ * Note that this method will block if no data is available. However,
+ * it will not necessarily block until it fills the entire buffer. That is,
+ * a "short count" is possible.
+ *
+ * @param buf The byte array to receive the data read
+ *
+ * @return The actual number fo bytes read or -1 if end of stream
+ *
+ * @exception IOException If an error occurs
+ */
+public abstract int
+read(byte[] buf) throws IOException;
+
+/*************************************************************************/
+
+/**
+ * This method reads raw bytes and stores them in a byte array buffer
+ * <code>buf</code> starting at position <code>offset</code> into the buffer. A
+ * maximum of <code>len</code> bytes will be read. Note that this method
+ * blocks if no data is available, but will not necessarily block until
+ * it can read <code>len</code> bytes of data. That is, a "short count" is
+ * possible.
+ *
+ * @param buf The byte array to receive the data read
+ * @param offset The offset into @code{buf} to start storing data
+ * @param len The maximum number of bytes to read
+ *
+ * @return The actual number fo bytes read or -1 if end of stream
+ *
+ * @exception IOException If an error occurs
+ */
+public abstract int
+read(byte[] buf, int offset, int len) throws IOException;
+
+/*************************************************************************/
+
+/**
+ * Reads an object instance and returns it. If the class for the object
+ * being read cannot be found, then a ClassNotFoundException will
+ * be thrown.
+ *
+ * @return The object instance that was read
+ *
+ * @exception ClassNotFoundException If a class for the object cannot be found
+ * @exception IOException If an error occurs
+ */
+public abstract Object
+readObject() throws ClassNotFoundException, IOException;
+
+/*************************************************************************/
+
+/**
+ * This method causes the specified number of bytes to be read and
+ * discarded. It is possible that fewer than the requested number of bytes
+ * will actually be skipped.
+ *
+ * @param num_bytes The number of bytes to skip
+ *
+ * @return The actual number of bytes skipped
+ *
+ * @exception IOException If an error occurs
+ */
+public abstract long
+skip(long num_bytes) throws IOException;
+
+/*************************************************************************/
+
+/**
+ * This method closes the input source
+ *
+ * @exception IOException If an error occurs
+ */
+public abstract void
+close() throws IOException;
+
+} // interface ObjectInput
+
diff --git a/libjava/java/io/ObjectInputStream.java b/libjava/java/io/ObjectInputStream.java
new file mode 100644
index 0000000..7855480
--- /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;
+ }
+}
diff --git a/libjava/java/io/ObjectInputValidation.java b/libjava/java/io/ObjectInputValidation.java
new file mode 100644
index 0000000..cf3508e
--- /dev/null
+++ b/libjava/java/io/ObjectInputValidation.java
@@ -0,0 +1,50 @@
+/* ObjectInputValidation.java -- Validate an object
+ Copyright (C) 1998 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;
+
+/**
+ * What does this interface really do?
+ *
+ * @version 0.0
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public abstract interface ObjectInputValidation
+{
+
+/**
+ * This method is called to validate an object. If the object is invalid
+ * an exception is thrown.
+ *
+ * @exception InvalidObjectException If the object is invalid
+ */
+public abstract void
+validateObject() throws InvalidObjectException;
+
+} // interface ObjectInputValidation
+
diff --git a/libjava/java/io/ObjectOutput.java b/libjava/java/io/ObjectOutput.java
new file mode 100644
index 0000000..56b3390
--- /dev/null
+++ b/libjava/java/io/ObjectOutput.java
@@ -0,0 +1,116 @@
+/* ObjectOutput.java -- Interface for writing objects to a stream
+ Copyright (C) 1998 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;
+
+/**
+ * This interface extends <code>DataOutput</code> to provide the additional
+ * facility of writing object instances to a stream. It also adds some
+ * additional methods to make the interface more <code>OutputStream</code> like.
+ *
+ * @version 0.0
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public abstract interface ObjectOutput extends DataOutput
+{
+
+
+/**
+ * This method writes the specified byte to the output stream.
+ *
+ * @param b The byte to write.
+ *
+ * @exception IOException If an error occurs.
+ */
+public abstract void
+write(int b) throws IOException;
+
+/*************************************************************************/
+
+/**
+ * This method writes all the bytes in the specified byte array to the
+ * output stream.
+ *
+ * @param buf The array of bytes to write.
+ *
+ * @exception IOException If an error occurs.
+ */
+public abstract void
+write(byte[] buf) throws IOException;
+
+/*************************************************************************/
+
+/**
+ * This method writes <code>len</code> bytes from the specified array
+ * starting at index <code>offset</code> into that array.
+ *
+ * @param buf The byte array to write from.
+ * @param offset The index into the byte array to start writing from.
+ * @param len The number of bytes to write.
+ *
+ * @exception IOException If an error occurs.
+ */
+public abstract void
+write(byte[] buf, int offset, int len) throws IOException;
+
+/*************************************************************************/
+
+/**
+ * This method writes a object instance to a stream. The format of the
+ * data written is determined by the actual implementation of this method
+ *
+ * @param obj The object to write
+ *
+ * @exception IOException If an error occurs
+ */
+public abstract void
+writeObject(Object obj) throws IOException;
+
+/*************************************************************************/
+
+/**
+ * This method causes any buffered data to be flushed out to the underlying
+ * stream
+ *
+ * @exception IOException If an error occurs
+ */
+public abstract void
+flush() throws IOException;
+
+/*************************************************************************/
+
+/**
+ * This method closes the underlying stream.
+ *
+ * @exception IOException If an error occurs
+ */
+public abstract void
+close() throws IOException;
+
+} // interface ObjectOutput
+
diff --git a/libjava/java/io/ObjectOutputStream.java b/libjava/java/io/ObjectOutputStream.java
new file mode 100644
index 0000000..a98b55ba
--- /dev/null
+++ b/libjava/java/io/ObjectOutputStream.java
@@ -0,0 +1,1335 @@
+/* ObjectOutputStream.java -- Class used to write 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.Field;
+import java.lang.reflect.Method;
+import java.util.Hashtable;
+
+import gnu.java.io.ObjectIdentityWrapper;
+import gnu.java.lang.reflect.TypeSignature;
+
+/**
+ An <code>ObjectOutputStream</code> can be used to write objects
+ as well as primitive data in a platform-independent manner to an
+ <code>OutputStream</code>.
+
+ The data produced by an <code>ObjectOutputStream</code> can be read
+ and reconstituted by an <code>ObjectInputStream</code>.
+
+ <code>writeObject (Object)</code> is used to write Objects, the
+ <code>write&lt;type&gt;</code> methods are used to write primitive
+ data (as in <code>DataOutputStream</code>). Strings can be written
+ as objects or as primitive data.
+
+ Not all objects can be written out using an
+ <code>ObjectOutputStream</code>. Only those objects that are an
+ instance of <code>java.io.Serializable</code> can be written.
+
+ Using default serialization, information about the class of an
+ object is written, all of the non-transient, non-static fields of
+ the object are written, if any of these fields are objects, the are
+ written out in the same manner.
+
+ An object is only written out the first time it is encountered. If
+ the object is encountered later, a reference to it is written to
+ the underlying stream. Thus writing circular object graphs
+ does not present a problem, nor are relationships between objects
+ in a graph lost.
+
+ Example usage:
+ <pre>
+ Hashtable map = new Hashtable ();
+ map.put ("one", new Integer (1));
+ map.put ("two", new Integer (2));
+
+ ObjectOutputStream oos =
+ new ObjectOutputStream (new FileOutputStream ("numbers"));
+ oos.writeObject (map);
+ oos.close ();
+
+ ObjectInputStream ois =
+ new ObjectInputStream (new FileInputStream ("numbers"));
+ Hashtable newmap = (Hashtable)ois.readObject ();
+
+ System.out.println (newmap);
+ </pre>
+
+ The default serialization can be overriden in two ways.
+
+ By defining a method <code>private void
+ writeObject (ObjectOutputStream)</code>, a class can dictate exactly
+ how information about itself is written.
+ <code>defaultWriteObject ()</code> may be called from this method to
+ carry out default serialization. This method is not
+ responsible for dealing with fields of super-classes or subclasses.
+
+ By implementing <code>java.io.Externalizable</code>. This gives
+ the class complete control over the way it is written to the
+ stream. If this approach is used the burden of writing superclass
+ and subclass data is transfered to the class implementing
+ <code>java.io.Externalizable</code>.
+
+ @see java.io.DataOutputStream
+ @see java.io.Externalizable
+ @see java.io.ObjectInputStream
+ @see java.io.Serializable
+ @see XXX: java serialization spec
+*/
+public class ObjectOutputStream extends OutputStream
+ implements ObjectOutput, ObjectStreamConstants
+{
+ /**
+ Creates a new <code>ObjectOutputStream</code> that will do all of
+ its writing onto <code>out</code>. This method also initializes
+ the stream by writing the header information (stream magic number
+ and stream version).
+
+ @exception IOException Writing stream header to underlying
+ stream cannot be completed.
+
+ @see writeStreamHeader ()
+ */
+ public ObjectOutputStream (OutputStream out) throws IOException
+ {
+ realOutput = new DataOutputStream (out);
+ blockData = new byte[ BUFFER_SIZE ];
+ blockDataCount = 0;
+ blockDataOutput = new DataOutputStream (this);
+ setBlockDataMode (true);
+ replacementEnabled = false;
+ isSerializing = false;
+ nextOID = baseWireHandle;
+ OIDLookupTable = new Hashtable ();
+ protocolVersion = defaultProtocolVersion;
+ useSubclassMethod = false;
+ writeStreamHeader ();
+ }
+
+
+ /**
+ Writes a representation of <code>obj</code> to the underlying
+ output stream by writing out information about its class, then
+ writing out each of the objects non-transient, non-static
+ fields. If any of these fields are other objects,
+ the are written out in the same manner.
+
+ This method can be overriden by a class by implementing
+ <code>private void writeObject (ObjectOutputStream)</code>.
+
+ If an exception is thrown from this method, the stream is left in
+ an undefined state.
+
+ @exception NotSerializableException An attempt was made to
+ serialize an <code>Object</code> that is not serializable.
+
+ @exception IOException Exception from underlying
+ <code>OutputStream</code>.
+ */
+ public final void writeObject (Object obj) throws IOException
+ {
+ if (useSubclassMethod)
+ {
+ writeObjectOverride (obj);
+ return;
+ }
+
+ boolean was_serializing = isSerializing;
+
+ if (! was_serializing)
+ setBlockDataMode (false);
+
+ try
+ {
+ isSerializing = true;
+ boolean replaceDone = false;
+
+ drain ();
+
+ while (true)
+ {
+ if (obj == null)
+ {
+ realOutput.writeByte (TC_NULL);
+ break;
+ }
+
+ Integer handle = findHandle (obj);
+ if (handle != null)
+ {
+ realOutput.writeByte (TC_REFERENCE);
+ realOutput.writeInt (handle.intValue ());
+ break;
+ }
+
+ if (obj instanceof Class)
+ {
+ realOutput.writeByte (TC_CLASS);
+ writeObject (ObjectStreamClass.lookup ((Class)obj));
+ assignNewHandle (obj);
+ break;
+ }
+
+ if (obj instanceof ObjectStreamClass)
+ {
+ ObjectStreamClass osc = (ObjectStreamClass)obj;
+ realOutput.writeByte (TC_CLASSDESC);
+ realOutput.writeUTF (osc.getName ());
+ realOutput.writeLong (osc.getSerialVersionUID ());
+ assignNewHandle (obj);
+
+ int flags = osc.getFlags ();
+
+ if (protocolVersion == PROTOCOL_VERSION_2
+ && osc.isExternalizable ())
+ flags |= SC_BLOCK_DATA;
+
+ realOutput.writeByte (flags);
+
+ ObjectStreamField[] fields = osc.fields;
+ realOutput.writeShort (fields.length);
+
+ ObjectStreamField field;
+ for (int i=0; i < fields.length; i++)
+ {
+ field = fields[i];
+ realOutput.writeByte (field.getTypeCode ());
+ realOutput.writeUTF (field.getName ());
+
+ if (! field.isPrimitive ())
+ writeObject (field.getTypeString ());
+ }
+
+ setBlockDataMode (true);
+ annotateClass (osc.forClass ());
+ setBlockDataMode (false);
+ realOutput.writeByte (TC_ENDBLOCKDATA);
+
+ if (osc.isSerializable ())
+ writeObject (osc.getSuper ());
+ else
+ writeObject (null);
+ break;
+ }
+
+
+ Object replacedObject = null;
+
+ if ((replacementEnabled || obj instanceof Replaceable)
+ && ! replaceDone)
+ {
+ replacedObject = obj;
+
+ if (obj instanceof Replaceable)
+ obj = ((Replaceable)obj).writeReplace ();
+
+ if (replacementEnabled)
+ obj = replaceObject (obj);
+
+ replaceDone = true;
+ continue;
+ }
+
+ if (obj instanceof String)
+ {
+ realOutput.writeByte (TC_STRING);
+ assignNewHandle (obj);
+ realOutput.writeUTF ((String)obj);
+ break;
+ }
+
+ Class clazz = obj.getClass ();
+ ObjectStreamClass osc = ObjectStreamClass.lookup (clazz);
+ if (osc == null)
+ throw new NotSerializableException ("The class "
+ + clazz.getName ()
+ + " is not Serializable");
+
+ if (clazz.isArray ())
+ {
+ realOutput.writeByte (TC_ARRAY);
+ writeObject (osc);
+ assignNewHandle (obj);
+ writeArraySizeAndElements (obj, clazz);
+ break;
+ }
+
+ realOutput.writeByte (TC_OBJECT);
+ writeObject (osc);
+
+ if (replaceDone)
+ assignNewHandle (replacedObject);
+ else
+ assignNewHandle (obj);
+
+ if (obj instanceof Externalizable)
+ {
+ if (protocolVersion == PROTOCOL_VERSION_2)
+ setBlockDataMode (true);
+
+ ((Externalizable)obj).writeExternal (this);
+
+ if (protocolVersion == PROTOCOL_VERSION_2)
+ {
+ setBlockDataMode (false);
+ drain ();
+ }
+
+ break;
+ }
+
+ if (obj instanceof Serializable)
+ {
+ currentObject = obj;
+ ObjectStreamClass[] hierarchy =
+ ObjectStreamClass.getObjectStreamClasses (clazz);
+
+ boolean has_write;
+ for (int i=0; i < hierarchy.length; i++)
+ {
+ currentObjectStreamClass = hierarchy[i];
+
+ has_write = currentObjectStreamClass.hasWriteMethod ();
+ writeFields (obj, currentObjectStreamClass.fields,
+ has_write);
+
+ fieldsAlreadyWritten = false;
+
+ if (has_write)
+ {
+ drain ();
+ realOutput.writeByte (TC_ENDBLOCKDATA);
+ }
+ }
+
+ currentObject = null;
+ currentObjectStreamClass = null;
+ currentPutField = null;
+ break;
+ }
+
+ throw new NotSerializableException ("Instances of the class "
+ + clazz.getName ()
+ + " are not Serializable");
+ } // end pseudo-loop
+ }
+ catch (IOException e)
+ {
+ realOutput.writeByte (TC_EXCEPTION);
+ reset (true);
+
+ try
+ {
+ writeObject (e);
+ }
+ catch (IOException ioe)
+ {
+ throw new StreamCorruptedException ("Exception " + ioe + " thrown while exception was being written to stream.");
+ }
+
+ reset (true);
+ }
+ finally
+ {
+ isSerializing = was_serializing;
+
+ if (! was_serializing)
+ setBlockDataMode (true);
+ }
+ }
+
+
+ /**
+ Writes the current objects non-transient, non-static fields from
+ the current class to the underlying output stream.
+
+ This method is intended to be called from within a object's
+ <code>private void writeObject (ObjectOutputStream)</code>
+ method.
+
+ @exception NotActiveException This method was called from a
+ context other than from the current object's and current class's
+ <code>private void writeObject (ObjectOutputStream)</code>
+ method.
+
+ @exception IOException Exception from underlying
+ <code>OutputStream</code>.
+ */
+ public void defaultWriteObject ()
+ throws IOException, NotActiveException
+ {
+ markFieldsWritten ();
+ writeFields (currentObject, currentObjectStreamClass.fields, false);
+ }
+
+
+ private void markFieldsWritten () throws IOException
+ {
+ if (currentObject == null || currentObjectStreamClass == null)
+ throw new NotActiveException ("defaultWriteObject called by non-active class and/or object");
+
+ if (fieldsAlreadyWritten)
+ throw new IOException ("Only one of putFields and defalutWriteObject may be called, and it may only be called once");
+
+ fieldsAlreadyWritten = true;
+ }
+
+
+ /**
+ Resets stream to state equivalent to the state just after it was
+ constructed.
+
+ Causes all objects previously written to the stream to be
+ forgotten. A notification of this reset is also written to the
+ underlying stream.
+
+ @exception IOException Exception from underlying
+ <code>OutputStream</code> or reset called while serialization is
+ in progress.
+ */
+ public void reset () throws IOException
+ {
+ reset (false);
+ }
+
+
+ private void reset (boolean internal) throws IOException
+ {
+ if (!internal)
+ {
+ if (isSerializing)
+ throw new IOException ("Reset called while serialization in progress");
+
+ realOutput.writeByte (TC_RESET);
+ }
+
+ clearHandles ();
+ }
+
+
+ /**
+ Informs this <code>ObjectOutputStream</code> to write data
+ according to the specified protocol. There are currently two
+ different protocols, specified by <code>PROTOCOL_VERSION_1</code>
+ and <code>PROTOCOL_VERSION_2</code>. This implementation writes
+ data using <code>PROTOCOL_VERSION_1</code> by default, as is done
+ by the JDK 1.1.
+
+ A non-portable method, <code>setDefaultProtocolVersion (int
+ version)</code> is provided to change the default protocol
+ version.
+
+ For an explination of the differences beween the two protocols
+ see XXX: the Java ObjectSerialization Specification.
+
+ @exception IOException if <code>version</code> is not a valid
+ protocol
+
+ @see setDefaultProtocolVersion (int)
+ */
+ public void useProtocolVersion (int version) throws IOException
+ {
+ if (version != PROTOCOL_VERSION_1 && version != PROTOCOL_VERSION_2)
+ throw new IOException ("Invalid protocol version requested.");
+
+ protocolVersion = version;
+ }
+
+
+ /**
+ <em>GNU $classpath specific</em>
+
+ Changes the default stream protocol used by all
+ <code>ObjectOutputStream</code>s. There are currently two
+ different protocols, specified by <code>PROTOCOL_VERSION_1</code>
+ and <code>PROTOCOL_VERSION_2</code>. The default default is
+ <code>PROTOCOL_VERSION_1</code>.
+
+ @exception IOException if <code>version</code> is not a valid
+ protocol
+
+ @see useProtocolVersion (int)
+ */
+ public static void setDefaultProtocolVersion (int version)
+ throws IOException
+ {
+ if (version != PROTOCOL_VERSION_1 && version != PROTOCOL_VERSION_2)
+ throw new IOException ("Invalid protocol version requested.");
+
+ defaultProtocolVersion = version;
+ }
+
+
+ /**
+ An empty hook that allows subclasses to write extra information
+ about classes to the stream. This method is called the first
+ time each class is seen, and after all of the standard
+ information about the class has been written.
+
+ @exception IOException Exception from underlying
+ <code>OutputStream</code>.
+
+ @see java.io.ObjectInputStream#resolveClass (java.io.ObjectStreamClass)
+ */
+ protected void annotateClass (Class cl) throws IOException
+ {}
+
+
+ /**
+ Allows subclasses to replace objects that are written to the
+ stream with other objects to be written in their place. This
+ method is called the first time each object is encountered
+ (modulo reseting of the stream).
+
+ This method must be enabled before it will be called in the
+ serialization process.
+
+ @exception IOException Exception from underlying
+ <code>OutputStream</code>.
+
+ @see enableReplaceObject (boolean)
+ */
+ protected Object replaceObject (Object obj) throws IOException
+ {
+ return obj;
+ }
+
+
+ /**
+ If <code>enable</code> is <code>true</code> and this object is
+ trusted, then <code>replaceObject (Object)</code> will be called
+ in subsequent calls to <code>writeObject (Object)</code>.
+ Otherwise, <code>replaceObject (Object)</code> will not be called.
+
+ @exception SecurityException This class is not trusted.
+ */
+ protected boolean enableReplaceObject (boolean enable)
+ throws SecurityException
+ {
+ if (enable)
+ if (getClass ().getClassLoader () != null)
+ throw new SecurityException ("Untrusted ObjectOutputStream subclass attempted to enable object replacement");
+
+ boolean old_val = replacementEnabled;
+ replacementEnabled = enable;
+ return old_val;
+ }
+
+
+ /**
+ Writes stream magic and stream version information to the
+ underlying stream.
+
+ @exception IOException Exception from underlying
+ <code>OutputStream</code>.
+ */
+ protected void writeStreamHeader () throws IOException
+ {
+ realOutput.writeShort (STREAM_MAGIC);
+ realOutput.writeShort (STREAM_VERSION);
+ }
+
+
+
+ /**
+ Protected constructor that allows subclasses to override
+ serialization. This constructor should be called by subclasses
+ that wish to override <code>writeObject (Object)</code>. This
+ method does a security check <i>NOTE: currently not
+ implemented</i>, then sets a flag that informs
+ <code>writeObject (Object)</code> to call the subclasses
+ <code>writeObjectOverride (Object)</code> method.
+
+ @see writeObjectOverride (Object)
+ */
+ protected ObjectOutputStream () throws IOException, SecurityException
+ {
+ SecurityManager sec_man = System.getSecurityManager ();
+ if (sec_man != null)
+ sec_man.checkPermission (SUBCLASS_IMPLEMENTATION_PERMISSION);
+ useSubclassMethod = true;
+ }
+
+
+ /**
+ This method allows subclasses to override the default
+ serialization mechanism provided by
+ <code>ObjectOutputStream</code>. To make this method be used for
+ writing objects, subclasses must invoke the 0-argument
+ constructor on this class from there constructor.
+
+ @see ObjectOutputStream ()
+
+ @exception NotActiveException Subclass has arranged for this
+ method to be called, but did not implement this method.
+ */
+ protected void writeObjectOverride (Object obj) throws NotActiveException,
+ IOException
+ {
+ throw new NotActiveException ("Subclass of ObjectOutputStream must implement writeObjectOverride");
+ }
+
+
+ /**
+ @see java.io.DataOutputStream#write (int)
+ */
+ public void write (int data) throws IOException
+ {
+ if (writeDataAsBlocks)
+ {
+ if (blockDataCount == BUFFER_SIZE)
+ drain ();
+
+ blockData[ blockDataCount++ ] = (byte)data;
+ }
+ else
+ realOutput.write (data);
+ }
+
+
+ /**
+ @see java.io.DataOutputStream#write (byte[])
+ */
+ public void write (byte b[]) throws IOException
+ {
+ write (b, 0, b.length);
+ }
+
+
+ /**
+ @see java.io.DataOutputStream#write (byte[],int,int)
+ */
+ public void write (byte b[], int off, int len) throws IOException
+ {
+ if (writeDataAsBlocks)
+ {
+ if (len < 0)
+ throw new IndexOutOfBoundsException ();
+
+ if (blockDataCount + len < BUFFER_SIZE)
+ {
+ System.arraycopy (b, off, blockData, blockDataCount, len);
+ blockDataCount += len;
+ }
+ else
+ {
+ drain ();
+ writeBlockDataHeader (len);
+ realOutput.write (b, off, len);
+ }
+ }
+ else
+ realOutput.write (b, off, len);
+ }
+
+
+ /**
+ @see java.io.DataOutputStream#flush ()
+ */
+ public void flush () throws IOException
+ {
+ drain ();
+ realOutput.flush ();
+ }
+
+
+ /**
+ Causes the block-data buffer to be written to the underlying
+ stream, but does not flush underlying stream.
+
+ @exception IOException Exception from underlying
+ <code>OutputStream</code>.
+ */
+ protected void drain () throws IOException
+ {
+ if (blockDataCount == 0)
+ return;
+
+ writeBlockDataHeader (blockDataCount);
+ realOutput.write (blockData, 0, blockDataCount);
+ blockDataCount = 0;
+ }
+
+
+ /**
+ @see java.io.DataOutputStream#close ()
+ */
+ public void close () throws IOException
+ {
+ drain ();
+ realOutput.close ();
+ }
+
+
+ /**
+ @see java.io.DataOutputStream#writeBoolean (boolean)
+ */
+ public void writeBoolean (boolean data) throws IOException
+ {
+ dataOutput.writeBoolean (data);
+ }
+
+
+ /**
+ @see java.io.DataOutputStream#writeByte (int)
+ */
+ public void writeByte (int data) throws IOException
+ {
+ dataOutput.writeByte (data);
+ }
+
+
+ /**
+ @see java.io.DataOutputStream#writeShort (int)
+ */
+ public void writeShort (int data) throws IOException
+ {
+ dataOutput.writeShort (data);
+ }
+
+
+ /**
+ @see java.io.DataOutputStream#writeChar (int)
+ */
+ public void writeChar (int data) throws IOException
+ {
+ dataOutput.writeChar (data);
+ }
+
+
+ /**
+ @see java.io.DataOutputStream#writeInt (int)
+ */
+ public void writeInt (int data) throws IOException
+ {
+ dataOutput.writeInt (data);
+ }
+
+
+ /**
+ @see java.io.DataOutputStream#writeLong (long)
+ */
+ public void writeLong (long data) throws IOException
+ {
+ dataOutput.writeLong (data);
+ }
+
+
+ /**
+ @see java.io.DataOutputStream#writeFloat (float)
+ */
+ public void writeFloat (float data) throws IOException
+ {
+ dataOutput.writeFloat (data);
+ }
+
+
+ /**
+ @see java.io.DataOutputStream#writeDouble (double)
+ */
+ public void writeDouble (double data) throws IOException
+ {
+ dataOutput.writeDouble (data);
+ }
+
+
+ /**
+ @see java.io.DataOutputStream#writeBytes (java.lang.String)
+ */
+ public void writeBytes (String data) throws IOException
+ {
+ dataOutput.writeBytes (data);
+ }
+
+
+ /**
+ @see java.io.DataOutputStream#writeChars (java.lang.String)
+ */
+ public void writeChars (String data) throws IOException
+ {
+ dataOutput.writeChars (data);
+ }
+
+
+ /**
+ @see java.io.DataOutputStream#writeUTF (java.lang.String)
+ */
+ public void writeUTF (String data) throws IOException
+ {
+ dataOutput.writeUTF (data);
+ }
+
+
+ /**
+ This class allows a class to specify exactly which fields should
+ be written, and what values should be written for these fields.
+
+ XXX: finish up comments
+ */
+ public static abstract class PutField
+ {
+ public abstract void put (String name, boolean value)
+ throws IOException, IllegalArgumentException;
+ public abstract void put (String name, byte value)
+ throws IOException, IllegalArgumentException;
+ public abstract void put (String name, char value)
+ throws IOException, IllegalArgumentException;
+ public abstract void put (String name, double value)
+ throws IOException, IllegalArgumentException;
+ public abstract void put (String name, float value)
+ throws IOException, IllegalArgumentException;
+ public abstract void put (String name, int value)
+ throws IOException, IllegalArgumentException;
+ public abstract void put (String name, long value)
+ throws IOException, IllegalArgumentException;
+ public abstract void put (String name, short value)
+ throws IOException, IllegalArgumentException;
+ public abstract void put (String name, Object value)
+ throws IOException, IllegalArgumentException;
+ public abstract void write (ObjectOutput out) throws IOException;
+ }
+
+
+ public PutField putFields () throws IOException
+ {
+ markFieldsWritten ();
+
+ currentPutField = new PutField ()
+ {
+ private byte[] prim_field_data
+ = new byte[currentObjectStreamClass.primFieldSize];
+ private Object[] objs
+ = new Object[currentObjectStreamClass.objectFieldCount];
+
+ public void put (String name, boolean value)
+ throws IOException, IllegalArgumentException
+ {
+ ObjectStreamField field
+ = currentObjectStreamClass.getField (name);
+ checkType (field, 'Z');
+ prim_field_data[field.getOffset ()] = (byte)(value ? 1 : 0);
+ }
+
+ public void put (String name, byte value)
+ throws IOException, IllegalArgumentException
+ {
+ ObjectStreamField field
+ = currentObjectStreamClass.getField (name);
+ checkType (field, 'B');
+ prim_field_data[field.getOffset ()] = value;
+ }
+
+ public void put (String name, char value)
+ throws IOException, IllegalArgumentException
+ {
+ ObjectStreamField field
+ = currentObjectStreamClass.getField (name);
+ checkType (field, 'B');
+ int off = field.getOffset ();
+ prim_field_data[off++] = (byte)(value >>> 8);
+ prim_field_data[off] = (byte)value;
+ }
+
+ public void put (String name, double value)
+ throws IOException, IllegalArgumentException
+ {
+ ObjectStreamField field
+ = currentObjectStreamClass.getField (name);
+ checkType (field, 'B');
+ int off = field.getOffset ();
+ long l_value = Double.doubleToLongBits (value);
+ prim_field_data[off++] = (byte)(l_value >>> 52);
+ prim_field_data[off++] = (byte)(l_value >>> 48);
+ prim_field_data[off++] = (byte)(l_value >>> 40);
+ prim_field_data[off++] = (byte)(l_value >>> 32);
+ prim_field_data[off++] = (byte)(l_value >>> 24);
+ prim_field_data[off++] = (byte)(l_value >>> 16);
+ prim_field_data[off++] = (byte)(l_value >>> 8);
+ prim_field_data[off] = (byte)l_value;
+ }
+
+ public void put (String name, float value)
+ throws IOException, IllegalArgumentException
+ {
+ ObjectStreamField field
+ = currentObjectStreamClass.getField (name);
+ checkType (field, 'B');
+ int off = field.getOffset ();
+ int i_value = Float.floatToIntBits (value);
+ prim_field_data[off++] = (byte)(i_value >>> 24);
+ prim_field_data[off++] = (byte)(i_value >>> 16);
+ prim_field_data[off++] = (byte)(i_value >>> 8);
+ prim_field_data[off] = (byte)i_value;
+ }
+
+ public void put (String name, int value)
+ throws IOException, IllegalArgumentException
+ {
+ ObjectStreamField field
+ = currentObjectStreamClass.getField (name);
+ checkType (field, 'B');
+ int off = field.getOffset ();
+ prim_field_data[off++] = (byte)(value >>> 24);
+ prim_field_data[off++] = (byte)(value >>> 16);
+ prim_field_data[off++] = (byte)(value >>> 8);
+ prim_field_data[off] = (byte)value;
+ }
+
+ public void put (String name, long value)
+ throws IOException, IllegalArgumentException
+ {
+ ObjectStreamField field
+ = currentObjectStreamClass.getField (name);
+ checkType (field, 'B');
+ int off = field.getOffset ();
+ prim_field_data[off++] = (byte)(value >>> 52);
+ prim_field_data[off++] = (byte)(value >>> 48);
+ prim_field_data[off++] = (byte)(value >>> 40);
+ prim_field_data[off++] = (byte)(value >>> 32);
+ prim_field_data[off++] = (byte)(value >>> 24);
+ prim_field_data[off++] = (byte)(value >>> 16);
+ prim_field_data[off++] = (byte)(value >>> 8);
+ prim_field_data[off] = (byte)value;
+ }
+
+ public void put (String name, short value)
+ throws IOException, IllegalArgumentException
+ {
+ ObjectStreamField field
+ = currentObjectStreamClass.getField (name);
+ checkType (field, 'B');
+ int off = field.getOffset ();
+ prim_field_data[off++] = (byte)(value >>> 8);
+ prim_field_data[off] = (byte)value;
+ }
+
+ public void put (String name, Object value)
+ throws IOException, IllegalArgumentException
+ {
+ ObjectStreamField field
+ = currentObjectStreamClass.getField (name);
+ if (! field.getType ().isAssignableFrom (value.getClass ()))
+ throw new IllegalArgumentException ();
+ objs[field.getOffset ()] = value;
+ }
+
+ public void write (ObjectOutput out) throws IOException
+ {
+ out.write (prim_field_data);
+ for (int i = 0; i < objs.length; ++ i)
+ out.writeObject (objs[i]);
+ }
+
+ private void checkType (ObjectStreamField field, char type)
+ throws IllegalArgumentException
+ {
+ if (TypeSignature.getEncodingOfClass (field.getType ()).charAt (0) != type)
+ throw new IllegalArgumentException ();
+ }
+ };
+ // end PutFieldImpl
+
+ return currentPutField;
+ }
+
+
+ public void writeFields () throws IOException
+ {
+ if (currentPutField == null)
+ throw new NotActiveException ("writeFields can only be called after putFields has been called");
+
+ currentPutField.write (this);
+ }
+
+
+ // write out the block-data buffer, picking the correct header
+ // depending on the size of the buffer
+ private void writeBlockDataHeader (int size) throws IOException
+ {
+ if (size < 256)
+ {
+ realOutput.writeByte (TC_BLOCKDATA);
+ realOutput.write (size);
+ }
+ else
+ {
+ realOutput.writeByte (TC_BLOCKDATALONG);
+ realOutput.writeInt (size);
+ }
+ }
+
+
+ // lookup the handle for OBJ, return null if OBJ doesn't have a
+ // handle yet
+ private Integer findHandle (Object obj)
+ {
+ return (Integer)OIDLookupTable.get (new ObjectIdentityWrapper (obj));
+ }
+
+
+ // assigns the next availible handle to OBJ
+ private int assignNewHandle (Object obj)
+ {
+ OIDLookupTable.put (new ObjectIdentityWrapper (obj),
+ new Integer (nextOID));
+ return nextOID++;
+ }
+
+
+ // resets mapping from objects to handles
+ private void clearHandles ()
+ {
+ nextOID = baseWireHandle;
+ OIDLookupTable.clear ();
+ }
+
+
+ // write out array size followed by each element of the array
+ private void writeArraySizeAndElements (Object array, Class clazz)
+ throws IOException
+ {
+ int length = Array.getLength (array);
+
+ if (clazz.isPrimitive ())
+ {
+ if (clazz == Boolean.TYPE)
+ {
+ boolean[] cast_array = (boolean[])array;
+ realOutput.writeInt (length);
+ for (int i=0; i < length; i++)
+ realOutput.writeBoolean (cast_array[i]);
+ return;
+ }
+ if (clazz == Byte.TYPE)
+ {
+ byte[] cast_array = (byte[])array;
+ realOutput.writeInt (length);
+ for (int i=0; i < length; i++)
+ realOutput.writeByte (cast_array[i]);
+ return;
+ }
+ if (clazz == Character.TYPE)
+ {
+ char[] cast_array = (char[])array;
+ realOutput.writeInt (length);
+ for (int i=0; i < length; i++)
+ realOutput.writeChar (cast_array[i]);
+ return;
+ }
+ if (clazz == Double.TYPE)
+ {
+ double[] cast_array = (double[])array;
+ realOutput.writeInt (length);
+ for (int i=0; i < length; i++)
+ realOutput.writeDouble (cast_array[i]);
+ return;
+ }
+ if (clazz == Float.TYPE)
+ {
+ float[] cast_array = (float[])array;
+ realOutput.writeInt (length);
+ for (int i=0; i < length; i++)
+ realOutput.writeFloat (cast_array[i]);
+ return;
+ }
+ if (clazz == Integer.TYPE)
+ {
+ int[] cast_array = (int[])array;
+ realOutput.writeInt (length);
+ for (int i=0; i < length; i++)
+ realOutput.writeInt (cast_array[i]);
+ return;
+ }
+ if (clazz == Long.TYPE)
+ {
+ long[] cast_array = (long[])array;
+ realOutput.writeInt (length);
+ for (int i=0; i < length; i++)
+ realOutput.writeLong (cast_array[i]);
+ return;
+ }
+ if (clazz == Short.TYPE)
+ {
+ short[] cast_array = (short[])array;
+ realOutput.writeInt (length);
+ for (int i=0; i < length; i++)
+ realOutput.writeShort (cast_array[i]);
+ return;
+ }
+ }
+ else
+ {
+ Object[] cast_array = (Object[])array;
+ realOutput.writeInt (length);
+ for (int i=0; i < length; i++)
+ writeObject (cast_array[i]);
+ }
+ }
+
+
+ // writes out FIELDS of OBJECT. If CALL_WRITE_METHOD is true, use
+ // object's writeObject (ObjectOutputStream), otherwise use default
+ // serialization. FIELDS are already in canonical order.
+ private void writeFields (Object obj,
+ ObjectStreamField[] fields,
+ boolean call_write_method) throws IOException
+ {
+ if (call_write_method)
+ {
+ setBlockDataMode (true);
+ callWriteMethod (obj);
+ setBlockDataMode (false);
+ return;
+ }
+
+ String field_name;
+ Class type;
+ for (int i=0; i < fields.length; i++)
+ {
+ field_name = fields[i].getName ();
+ type = fields[i].getType ();
+
+ if (type == Boolean.TYPE)
+ realOutput.writeBoolean (getBooleanField (obj, field_name));
+ else if (type == Byte.TYPE)
+ realOutput.writeByte (getByteField (obj, field_name));
+ else if (type == Character.TYPE)
+ realOutput.writeChar (getCharField (obj, field_name));
+ else if (type == Double.TYPE)
+ realOutput.writeDouble (getDoubleField (obj, field_name));
+ else if (type == Float.TYPE)
+ realOutput.writeFloat (getFloatField (obj, field_name));
+ else if (type == Integer.TYPE)
+ realOutput.writeInt (getIntField (obj, field_name));
+ else if (type == Long.TYPE)
+ realOutput.writeLong (getLongField (obj, field_name));
+ else if (type == Short.TYPE)
+ realOutput.writeShort (getShortField (obj, field_name));
+ else
+ writeObject (getObjectField (obj, field_name,
+ TypeSignature.getEncodingOfClass (type)));
+ }
+ }
+
+
+ // Toggles writing primitive data to block-data buffer.
+ private void setBlockDataMode (boolean on)
+ {
+ writeDataAsBlocks = on;
+
+ if (on)
+ dataOutput = blockDataOutput;
+ else
+ dataOutput = realOutput;
+ }
+
+
+ private void callWriteMethod (Object obj) throws IOException
+ {
+ try
+ {
+ Class classArgs[] = {Class.forName ("java.io.ObjectOutputStream")};
+ Class klass = obj.getClass ();
+ Method m = getMethod (klass, "writeObject", classArgs);
+ if (m == null)
+ return;
+ Object args[] = {this};
+ m.invoke (obj, args);
+ }
+ catch (Exception _)
+ {
+ throw new IOException ();
+ }
+ }
+
+ private boolean getBooleanField (Object obj, String field_name) throws IOException
+ {
+ try
+ {
+ Class klass = obj.getClass ();
+ Field f = getField (klass, field_name);
+ boolean b = f.getBoolean (obj);
+ return b;
+ }
+ catch (Exception _)
+ {
+ throw new IOException ();
+ }
+ }
+
+ private byte getByteField (Object obj, String field_name) throws IOException
+ {
+ try
+ {
+ Class klass = obj.getClass ();
+ Field f = getField (klass, field_name);
+ byte b = f.getByte (obj);
+ return b;
+ }
+ catch (Exception _)
+ {
+ throw new IOException ();
+ }
+ }
+
+ private char getCharField (Object obj, String field_name) throws IOException
+ {
+ try
+ {
+ Class klass = obj.getClass ();
+ Field f = getField (klass, field_name);
+ char b = f.getChar (obj);
+ return b;
+ }
+ catch (Exception _)
+ {
+ throw new IOException ();
+ }
+ }
+
+ private double getDoubleField (Object obj, String field_name) throws IOException
+ {
+ try
+ {
+ Class klass = obj.getClass ();
+ Field f = getField (klass, field_name);
+ double b = f.getDouble (obj);
+ return b;
+ }
+ catch (Exception _)
+ {
+ throw new IOException ();
+ }
+ }
+
+ private float getFloatField (Object obj, String field_name) throws IOException
+ {
+ try
+ {
+ Class klass = obj.getClass ();
+ Field f = getField (klass, field_name);
+ float b = f.getFloat (obj);
+ return b;
+ }
+ catch (Exception _)
+ {
+ throw new IOException ();
+ }
+ }
+
+ private int getIntField (Object obj, String field_name) throws IOException
+ {
+ try
+ {
+ Class klass = obj.getClass ();
+ Field f = getField (klass, field_name);
+ int b = f.getInt (obj);
+ return b;
+ }
+ catch (Exception _)
+ {
+ throw new IOException ();
+ }
+ }
+
+ private long getLongField (Object obj, String field_name) throws IOException
+ {
+ try
+ {
+ Class klass = obj.getClass ();
+ Field f = getField (klass, field_name);
+ long b = f.getLong (obj);
+ return b;
+ }
+ catch (Exception _)
+ {
+ throw new IOException ();
+ }
+ }
+
+ private short getShortField (Object obj, String field_name) throws IOException
+ {
+ try
+ {
+ Class klass = obj.getClass ();
+ Field f = getField (klass, field_name);
+ short b = f.getShort (obj);
+ return b;
+ }
+ catch (Exception _)
+ {
+ throw new IOException ();
+ }
+ }
+
+ private Object getObjectField (Object obj, String field_name,
+ String type_code) throws IOException
+ {
+ try
+ {
+ Class klass = obj.getClass ();
+ Field f = getField (klass, field_name);
+ Object o = f.get (obj);
+ // FIXME: We should check the type_code here
+ return o;
+ }
+ catch (Exception _)
+ {
+ throw new IOException ();
+ }
+ }
+
+ 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;
+
+ // this value comes from 1.2 spec, but is used in 1.1 as well
+ private final static int BUFFER_SIZE = 1024;
+
+ private static int defaultProtocolVersion = PROTOCOL_VERSION_1;
+
+ private DataOutputStream dataOutput;
+ private boolean writeDataAsBlocks;
+ private DataOutputStream realOutput;
+ private DataOutputStream blockDataOutput;
+ private byte[] blockData;
+ private int blockDataCount;
+ private Object currentObject;
+ private ObjectStreamClass currentObjectStreamClass;
+ private PutField currentPutField;
+ private boolean fieldsAlreadyWritten;
+ private boolean replacementEnabled;
+ private boolean isSerializing;
+ private int nextOID;
+ private Hashtable OIDLookupTable;
+ private int protocolVersion;
+ private boolean useSubclassMethod;
+}
diff --git a/libjava/java/io/ObjectStreamClass.java b/libjava/java/io/ObjectStreamClass.java
new file mode 100644
index 0000000..f799b4f
--- /dev/null
+++ b/libjava/java/io/ObjectStreamClass.java
@@ -0,0 +1,666 @@
+/* ObjectStreamClass.java -- Class used to write class information
+ about 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.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.security.DigestOutputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Hashtable;
+import java.util.Vector;
+import gnu.java.io.NullOutputStream;
+import gnu.java.lang.reflect.TypeSignature;
+import gnu.gcj.io.SimpleSHSStream;
+
+
+public class ObjectStreamClass implements Serializable
+{
+ /**
+ Returns the <code>ObjectStreamClass</code> for <code>cl</code>.
+ If <code>cl</code> is null, or is not <code>Serializable</code>,
+ null is returned. <code>ObjectStreamClass</code>'s are memoized;
+ later calls to this method with the same class will return the
+ same <code>ObjectStreamClass</code> object and no recalculation
+ will be done.
+
+ @see java.io.Serializable
+ */
+ public static ObjectStreamClass lookup (Class cl)
+ {
+ if (cl == null)
+ return null;
+
+ ObjectStreamClass osc = (ObjectStreamClass)classLookupTable.get (cl);
+
+ if (osc != null)
+ return osc;
+ else if (! (Serializable.class).isAssignableFrom (cl))
+ return null;
+ else
+ {
+ osc = new ObjectStreamClass (cl);
+ classLookupTable.put (cl, osc);
+ return osc;
+ }
+ }
+
+
+ /**
+ Returns the name of the class that this
+ <code>ObjectStreamClass</code> represents.
+ */
+ public String getName ()
+ {
+ return name;
+ }
+
+
+ /**
+ Returns the class that this <code>ObjectStreamClass</code>
+ represents. Null could be returned if this
+ <code>ObjectStreamClass</code> was read from an
+ <code>ObjectInputStream</code> and the class it represents cannot
+ be found or loaded.
+
+ @see java.io.ObjectInputStream
+ */
+ public Class forClass ()
+ {
+ return clazz;
+ }
+
+
+ /**
+ Returns the serial version stream-unique identifier for the class
+ represented by this <code>ObjectStreamClass</code>. This SUID is
+ either defined by the class as <code>static final long
+ serialVersionUID</code> or is calculated as specified in
+ Javasoft's "Object Serialization Specification" XXX: add reference
+ */
+ public long getSerialVersionUID ()
+ {
+ return uid;
+ }
+
+
+ // Returns the serializable (non-static and non-transient) Fields
+ // of the class represented by this ObjectStreamClass. The Fields
+ // are sorted by name.
+ // XXX doc
+ public ObjectStreamField[] getFields ()
+ {
+ ObjectStreamField[] copy = new ObjectStreamField[ fields.length ];
+ System.arraycopy (fields, 0, copy, 0, fields.length);
+ return copy;
+ }
+
+
+ // XXX doc
+ // Can't do binary search since fields is sorted by name and
+ // primitiveness.
+ public ObjectStreamField getField (String name)
+ {
+ for (int i=0; i < fields.length; i++)
+ if (fields[i].getName ().equals (name))
+ return fields[i];
+ return null;
+ }
+
+
+ /**
+ Returns a textual representation of this
+ <code>ObjectStreamClass</code> object including the name of the
+ class it represents as well as that class's serial version
+ stream-unique identifier.
+
+ @see getSerialVersionUID ()
+ @see getName ()
+ */
+ public String toString ()
+ {
+ return "java.io.ObjectStreamClass< " + name + ", " + uid + " >";
+ }
+
+
+ // Returns true iff the class that this ObjectStreamClass represents
+ // has the following method:
+ //
+ // private void writeObject (ObjectOutputStream)
+ //
+ // This method is used by the class to override default
+ // serialization behaivior.
+ boolean hasWriteMethod ()
+ {
+ return (flags & ObjectStreamConstants.SC_WRITE_METHOD) != 0;
+ }
+
+
+ // Returns true iff the class that this ObjectStreamClass represents
+ // implements Serializable but does *not* implement Externalizable.
+ boolean isSerializable ()
+ {
+ return (flags & ObjectStreamConstants.SC_SERIALIZABLE) != 0;
+ }
+
+
+ // Returns true iff the class that this ObjectStreamClass represents
+ // implements Externalizable.
+ boolean isExternalizable ()
+ {
+ return (flags & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0;
+ }
+
+
+ // Returns the <code>ObjectStreamClass</code> that represents the
+ // class that is the superclass of the class this
+ // <code>ObjectStreamClass</cdoe> represents. If the superclass is
+ // not Serializable, null is returned.
+ ObjectStreamClass getSuper ()
+ {
+ return superClass;
+ }
+
+
+ // returns an array of ObjectStreamClasses that represent the super
+ // classes of CLAZZ and CLAZZ itself in order from most super to
+ // CLAZZ. ObjectStreamClass[0] is the highest superclass of CLAZZ
+ // that is serializable.
+ static ObjectStreamClass[] getObjectStreamClasses (Class clazz)
+ {
+ ObjectStreamClass osc = ObjectStreamClass.lookup (clazz);
+
+ ObjectStreamClass[] ret_val;
+
+ if (osc == null)
+ return new ObjectStreamClass[0];
+ else
+ {
+ Vector oscs = new Vector ();
+
+ while (osc != null)
+ {
+ oscs.addElement (osc);
+ osc = osc.getSuper ();
+ }
+
+ int count = oscs.size ();
+ ObjectStreamClass[] sorted_oscs = new ObjectStreamClass[ count ];
+
+ for (int i = count - 1; i >= 0; i--)
+ sorted_oscs[ count - i - 1 ] = (ObjectStreamClass)oscs.elementAt (i);
+
+ return sorted_oscs;
+ }
+ }
+
+
+ // Returns an integer that consists of bit-flags that indicate
+ // properties of the class represented by this ObjectStreamClass.
+ // The bit-flags that could be present are those defined in
+ // ObjectStreamConstants that begin with `SC_'
+ int getFlags ()
+ {
+ return flags;
+ }
+
+
+ ObjectStreamClass (String name, long uid, byte flags,
+ ObjectStreamField[] fields)
+ {
+ this.name = name;
+ this.uid = uid;
+ this.flags = flags;
+ this.fields = fields;
+ }
+
+
+ void setClass (Class clazz)
+ {
+ this.clazz = clazz;
+ }
+
+
+ void setSuperclass (ObjectStreamClass osc)
+ {
+ superClass = osc;
+ }
+
+
+ void calculateOffsets ()
+ {
+ int i;
+ ObjectStreamField field;
+ primFieldSize = 0;
+ int fcount = fields.length;
+ for (i = 0; i < fcount; ++ i)
+ {
+ field = fields[i];
+
+ if (! field.isPrimitive ())
+ break;
+
+ field.setOffset (primFieldSize);
+ switch (field.getTypeCode ())
+ {
+ case 'B':
+ case 'Z':
+ ++ primFieldSize;
+ break;
+ case 'C':
+ case 'S':
+ primFieldSize += 2;
+ break;
+ case 'I':
+ case 'F':
+ primFieldSize += 4;
+ break;
+ case 'D':
+ case 'J':
+ primFieldSize += 8;
+ break;
+ }
+ }
+
+ for (objectFieldCount = 0; i < fcount; ++ i)
+ fields[i].setOffset (objectFieldCount++);
+ }
+
+
+ private ObjectStreamClass (Class cl)
+ {
+ uid = 0;
+ flags = 0;
+
+ clazz = cl;
+ name = cl.getName ();
+ setFlags (cl);
+ setFields (cl);
+ setUID (cl);
+ superClass = lookup (cl.getSuperclass ());
+ }
+
+
+ // Sets bits in flags according to features of CL.
+ private void setFlags (Class cl)
+ {
+ if ((java.io.Externalizable.class).isAssignableFrom (cl))
+ flags |= ObjectStreamConstants.SC_EXTERNALIZABLE;
+ else if ((java.io.Serializable.class).isAssignableFrom (cl))
+ // only set this bit if CL is NOT Externalizable
+ flags |= ObjectStreamConstants.SC_SERIALIZABLE;
+
+ try
+ {
+ Method writeMethod = cl.getDeclaredMethod ("writeObject",
+ writeMethodArgTypes);
+ int modifiers = writeMethod.getModifiers ();
+
+ if (writeMethod.getReturnType () == Void.TYPE
+ && Modifier.isPrivate (modifiers)
+ && !Modifier.isStatic (modifiers))
+ flags |= ObjectStreamConstants.SC_WRITE_METHOD;
+ }
+ catch (NoSuchMethodException oh_well)
+ {}
+ }
+
+
+ // Sets fields to be a sorted array of the serializable fields of
+ // clazz.
+ private void setFields (Class cl)
+ {
+ if (! isSerializable () || isExternalizable ())
+ {
+ fields = NO_FIELDS;
+ return;
+ }
+
+ try
+ {
+ Field serialPersistantFields
+ = cl.getDeclaredField ("serialPersistantFields");
+ int modifiers = serialPersistantFields.getModifiers ();
+
+ if (Modifier.isStatic (modifiers)
+ && Modifier.isFinal (modifiers)
+ && Modifier.isPrivate (modifiers))
+ {
+ fields = getSerialPersistantFields (cl);
+ Arrays.sort (fields);
+ calculateOffsets ();
+ return;
+ }
+ }
+ catch (NoSuchFieldException ignore)
+ {}
+
+ int num_good_fields = 0;
+ Field[] all_fields = cl.getDeclaredFields ();
+
+ int modifiers;
+ // set non-serializable fields to null in all_fields
+ for (int i=0; i < all_fields.length; i++)
+ {
+ modifiers = all_fields[i].getModifiers ();
+ if (Modifier.isTransient (modifiers)
+ || Modifier.isStatic (modifiers))
+ all_fields[i] = null;
+ else
+ num_good_fields++;
+ }
+
+ // make a copy of serializable (non-null) fields
+ fields = new ObjectStreamField[ num_good_fields ];
+ for (int from=0, to=0; from < all_fields.length; from++)
+ if (all_fields[from] != null)
+ {
+ Field f = all_fields[from];
+ fields[to] = new ObjectStreamField (f.getName (), f.getType ());
+ to++;
+ }
+
+ Arrays.sort (fields);
+ calculateOffsets ();
+ }
+
+ // Sets uid be serial version UID defined by class, or if that
+ // isn't present, calculates value of serial version UID.
+ private void setUID (Class cl)
+ {
+ try
+ {
+ Field suid = cl.getDeclaredField ("serialVersionUID");
+ int modifiers = suid.getModifiers ();
+
+ if (Modifier.isStatic (modifiers)
+ && Modifier.isFinal (modifiers))
+ {
+ uid = getDefinedSUID (cl);
+ return;
+ }
+ }
+ catch (NoSuchFieldException ignore)
+ {}
+
+ // cl didn't define serialVersionUID, so we have to compute it
+ try
+ {
+ MessageDigest md = null;
+ DigestOutputStream digest_out = null;
+ DataOutputStream data_out = null;
+ SimpleSHSStream simple = null;
+
+ try
+ {
+ md = MessageDigest.getInstance ("SHA");
+ digest_out = new DigestOutputStream (nullOutputStream, md);
+ data_out = new DataOutputStream (digest_out);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ simple = new SimpleSHSStream (nullOutputStream);
+ data_out = new DataOutputStream (simple);
+ }
+
+ data_out.writeUTF (cl.getName ());
+
+ int modifiers = cl.getModifiers ();
+ // just look at interesting bits
+ modifiers = modifiers & (Modifier.ABSTRACT | Modifier.FINAL
+ | Modifier.INTERFACE | Modifier.PUBLIC);
+ data_out.writeInt (modifiers);
+
+ Class[] interfaces = cl.getInterfaces ();
+ Arrays.sort (interfaces, interfaceComparator);
+ for (int i=0; i < interfaces.length; i++)
+ data_out.writeUTF (interfaces[i].getName ());
+
+
+ Field field;
+ Field[] fields = cl.getDeclaredFields ();
+ Arrays.sort (fields, memberComparator);
+ for (int i=0; i < fields.length; i++)
+ {
+ field = fields[i];
+ modifiers = field.getModifiers ();
+ if (Modifier.isPrivate (modifiers)
+ && (Modifier.isStatic (modifiers)
+ || Modifier.isTransient (modifiers)))
+ continue;
+
+ data_out.writeUTF (field.getName ());
+ data_out.writeInt (modifiers);
+ data_out.writeUTF (TypeSignature.getEncodingOfClass (field.getType ()));
+ }
+
+ // write class initializer method if present
+ boolean has_init;
+ try
+ {
+ has_init = hasClassInitializer (cl);
+ }
+ catch (NoSuchMethodError e)
+ {
+ has_init = false;
+ }
+
+ if (has_init)
+ {
+ data_out.writeUTF ("<clinit>");
+ data_out.writeInt (Modifier.STATIC);
+ data_out.writeUTF ("()V");
+ }
+
+ Constructor constructor;
+ Constructor[] constructors = cl.getDeclaredConstructors ();
+ Arrays.sort (constructors, memberComparator);
+ for (int i=0; i < constructors.length; i++)
+ {
+ constructor = constructors[i];
+ modifiers = constructor.getModifiers ();
+ if (Modifier.isPrivate (modifiers))
+ continue;
+
+ data_out.writeUTF ("<init>");
+ data_out.writeInt (modifiers);
+
+ // the replacement of '/' with '.' was needed to make computed
+ // SUID's agree with those computed by JDK
+ data_out.writeUTF (
+ TypeSignature.getEncodingOfConstructor (constructor).replace ('/','.'));
+ }
+
+ Method method;
+ Method[] methods = cl.getDeclaredMethods ();
+ Arrays.sort (methods, memberComparator);
+ for (int i=0; i < methods.length; i++)
+ {
+ method = methods[i];
+ modifiers = method.getModifiers ();
+ if (Modifier.isPrivate (modifiers))
+ continue;
+
+ data_out.writeUTF (method.getName ());
+ data_out.writeInt (modifiers);
+
+ // the replacement of '/' with '.' was needed to make computed
+ // SUID's agree with those computed by JDK
+ data_out.writeUTF (
+ TypeSignature.getEncodingOfMethod (method).replace ('/', '.'));
+ }
+
+ data_out.close ();
+ byte[] sha = md != null ? md.digest () : simple.digest ();
+ long result = 0;
+ int len = sha.length < 8 ? sha.length : 8;
+ for (int i=0; i < len; i++)
+ result += (long)(sha[i] & 0xFF) << (8 * i);
+
+ uid = result;
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new RuntimeException ("The SHA algorithm was not found to use in computing the Serial Version UID for class "
+ + cl.getName ());
+ }
+ catch (IOException ioe)
+ {
+ throw new RuntimeException (ioe.getMessage ());
+ }
+ }
+
+
+ // Returns the value of CLAZZ's final static long field named
+ // `serialVersionUID'.
+ private long getDefinedSUID (Class clazz)
+ {
+ long l = 0;
+ try
+ {
+ // Use getDeclaredField rather than getField, since serialVersionUID
+ // may not be public AND we only want the serialVersionUID of this
+ // class, not a superclass or interface.
+ Field f = clazz.getDeclaredField ("serialVersionUID");
+ l = f.getLong (null);
+ }
+ catch (java.lang.NoSuchFieldException e)
+ {
+ }
+
+ catch (java.lang.IllegalAccessException e)
+ {
+ }
+
+ return l;
+ }
+
+ // Returns the value of CLAZZ's private static final field named
+ // `serialPersistantFields'.
+ private ObjectStreamField[] getSerialPersistantFields (Class clazz)
+ {
+ ObjectStreamField[] o = null;
+ try
+ {
+ // Use getDeclaredField rather than getField for the same reason
+ // as above in getDefinedSUID.
+ Field f = clazz.getDeclaredField ("getSerialPersistantFields");
+ o = (ObjectStreamField[])f.get (null);
+ }
+ catch (java.lang.NoSuchFieldException e)
+ {
+ }
+ catch (java.lang.IllegalAccessException e)
+ {
+ }
+
+ return o;
+ }
+
+
+ // Returns true if CLAZZ has a static class initializer
+ // (a.k.a. <clinit>).
+ //
+ // A NoSuchMethodError is raised if CLAZZ has no such method.
+ private static boolean hasClassInitializer (Class clazz)
+ throws java.lang.NoSuchMethodError
+ {
+ Method m = null;
+
+ try
+ {
+ Class classArgs[] = {};
+ m = clazz.getMethod ("<clinit>", classArgs);
+ }
+ catch (java.lang.NoSuchMethodException e)
+ {
+ throw new java.lang.NoSuchMethodError ();
+ }
+
+ return m != null;
+ }
+
+ public static final ObjectStreamField[] NO_FIELDS = {};
+
+ private static Hashtable classLookupTable = new Hashtable ();
+ private static final NullOutputStream nullOutputStream = new NullOutputStream ();
+ private static final Comparator interfaceComparator = new InterfaceComparator ();
+ private static final Comparator memberComparator = new MemberComparator ();
+ private static final
+ Class[] writeMethodArgTypes = { java.io.ObjectOutputStream.class };
+
+ private ObjectStreamClass superClass;
+ private Class clazz;
+ private String name;
+ private long uid;
+ private byte flags;
+
+ // this field is package protected so that ObjectInputStream and
+ // ObjectOutputStream can access it directly
+ ObjectStreamField[] fields;
+
+ // these are accessed by ObjectIn/OutputStream
+ int primFieldSize = -1; // -1 if not yet calculated
+ int objectFieldCount;
+}
+
+
+// interfaces are compared only by name
+class InterfaceComparator implements Comparator
+{
+ public int compare (Object o1, Object o2)
+ {
+ return ((Class)o1).getName ().compareTo (((Class)o2).getName ());
+ }
+}
+
+
+// Members (Methods and Constructors) are compared first by name,
+// conflicts are resolved by comparing type signatures
+class MemberComparator implements Comparator
+{
+ public int compare (Object o1, Object o2)
+ {
+ Member m1 = (Member)o1;
+ Member m2 = (Member)o2;
+
+ int comp = m1.getName ().compareTo (m2.getName ());
+
+ if (comp == 0)
+ return TypeSignature.getEncodingOfMember (m1).
+ compareTo (TypeSignature.getEncodingOfMember (m2));
+ else
+ return comp;
+ }
+}
diff --git a/libjava/java/io/ObjectStreamConstants.java b/libjava/java/io/ObjectStreamConstants.java
new file mode 100644
index 0000000..c9a2aea
--- /dev/null
+++ b/libjava/java/io/ObjectStreamConstants.java
@@ -0,0 +1,74 @@
+/* ObjectStreamConstants.java -- Interface containing constant values
+ used in reading and writing 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;
+
+/**
+ This interface contains constants that are used in object
+ serialization. This interface is used by ObjectOutputStream,
+ ObjectInputStream, ObjectStreamClass, and possibly other classes.
+ The values for these constants are specified in Javasoft's "Object
+ Serialization Specification" TODO: add reference
+*/
+public interface ObjectStreamConstants
+{
+ public final static int PROTOCOL_VERSION_1 = 1;
+ public final static int PROTOCOL_VERSION_2 = 2;
+
+ final static short STREAM_MAGIC = (short)0xaced;
+ final static short STREAM_VERSION = 5;
+
+ final static byte TC_NULL = (byte)112;
+ final static byte TC_REFERENCE = (byte)113;
+ final static byte TC_CLASSDESC = (byte)114;
+ final static byte TC_OBJECT = (byte)115;
+ final static byte TC_STRING = (byte)116;
+ final static byte TC_ARRAY = (byte)117;
+ final static byte TC_CLASS = (byte)118;
+ final static byte TC_BLOCKDATA = (byte)119;
+ final static byte TC_ENDBLOCKDATA = (byte)120;
+ final static byte TC_RESET = (byte)121;
+ final static byte TC_BLOCKDATALONG = (byte)122;
+ final static byte TC_EXCEPTION = (byte)123;
+
+ final static byte TC_BASE = TC_NULL;
+ final static byte TC_MAX = TC_EXCEPTION;
+
+ final static int baseWireHandle = 0x7e0000;
+
+ final static byte SC_WRITE_METHOD = 0x01;
+ final static byte SC_SERIALIZABLE = 0x02;
+ final static byte SC_EXTERNALIZABLE = 0x04;
+ final static byte SC_BLOCK_DATA = 0x08;
+
+ final static SerializablePermission SUBSTITUTION_PERMISSION
+ = new SerializablePermission("enableSubstitution");
+
+ final static SerializablePermission SUBCLASS_IMPLEMENTATION_PERMISSION
+ = new SerializablePermission("enableSubclassImplementation");
+}
diff --git a/libjava/java/io/ObjectStreamField.java b/libjava/java/io/ObjectStreamField.java
new file mode 100644
index 0000000..55181cc
--- /dev/null
+++ b/libjava/java/io/ObjectStreamField.java
@@ -0,0 +1,99 @@
+/* ObjectStreamField.java -- Class used to store name and class of fields
+ 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 gnu.java.lang.reflect.TypeSignature;
+
+// XXX doc
+public class ObjectStreamField implements java.lang.Comparable
+{
+ public ObjectStreamField (String name, Class type)
+ {
+ this.name = name;
+ this.type = type;
+ }
+
+ public String getName ()
+ {
+ return name;
+ }
+
+ public Class getType ()
+ {
+ return type;
+ }
+
+ public char getTypeCode ()
+ {
+ return TypeSignature.getEncodingOfClass (type).charAt (0);
+ }
+
+ public String getTypeString ()
+ {
+ return TypeSignature.getEncodingOfClass (type);
+ }
+
+ public int getOffset ()
+ {
+ return offset;
+ }
+
+ protected void setOffset (int off)
+ {
+ offset = off;
+ }
+
+ public boolean isPrimitive ()
+ {
+ return type.isPrimitive ();
+ }
+
+ public int compareTo (Object o)
+ {
+ ObjectStreamField f = (ObjectStreamField)o;
+ boolean this_is_primitive = isPrimitive ();
+ boolean f_is_primitive = f.isPrimitive ();
+
+ if (this_is_primitive && !f_is_primitive)
+ return -1;
+
+ if (!this_is_primitive && f_is_primitive)
+ return 1;
+
+ return getName ().compareTo (f.getName ());
+ }
+
+ public String toString ()
+ {
+ return "ObjectStreamField< " + type + " " + name + " >";
+ }
+
+ private String name;
+ private Class type;
+ private int offset = -1; // XXX make sure this is correct
+}
diff --git a/libjava/java/io/Replaceable.java b/libjava/java/io/Replaceable.java
new file mode 100644
index 0000000..1035ab5
--- /dev/null
+++ b/libjava/java/io/Replaceable.java
@@ -0,0 +1,54 @@
+/* Replaceable.java -- Replace an object with another object
+ Copyright (C) 1998 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;
+
+/**
+ * This interface is used to indicate that an object may want to have
+ * another object serialized instead of itself. It contains one method
+ * that is to be called when an object is to be serialized. That method
+ * is reponsible for returning the real object that should be serialized
+ * instead of object being queried.
+ *
+ * @version 0.0
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public interface Replaceable extends Serializable
+{
+
+/**
+ * This method returns the object that should be serialized instead of
+ * this object
+ *
+ * @return The real object that should be serialized
+ */
+public abstract Object
+writeReplace();
+
+} // interface Replaceable
+
diff --git a/libjava/java/io/Resolvable.java b/libjava/java/io/Resolvable.java
new file mode 100644
index 0000000..b7250de6
--- /dev/null
+++ b/libjava/java/io/Resolvable.java
@@ -0,0 +1,52 @@
+/* Resolvable.java -- Returns an object to replace the one being de-serialized
+ Copyright (C) 1998 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;
+
+/**
+ * This interface is implemented when an object wishes to return another
+ * object to replace it during de-serialization. It has one method that
+ * returns the object that should be used to replace the original object.
+ *
+ * @version 0.0
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public interface Resolvable extends Serializable
+{
+
+/**
+ * This method returns the object that should be used to replace the
+ * original object during de-serialization.
+ *
+ * @return The replacement object
+ */
+public abstract Object
+readResolve();
+
+} // interface Resolvable
+
diff --git a/libjava/java/io/SerializablePermission.java b/libjava/java/io/SerializablePermission.java
new file mode 100644
index 0000000..78c7229
--- /dev/null
+++ b/libjava/java/io/SerializablePermission.java
@@ -0,0 +1,106 @@
+/* SerializablePermission.java -- Basic permissions related to serialization.
+ Copyright (C) 1998 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.security.BasicPermission;
+
+/**
+ * This class models permissions related to serialization. As a subclass
+ * of <code>BasicPermission</code>, this class has permissions that have
+ * a name only. There is no associated action list.
+ * <p>
+ * There are currently two allowable permission names for this class:
+ * <ul>
+ * <li><code>enableSubclassImplementation</code> - Allows a subclass to
+ * override the default serialization behavior of objects.
+ * <li><code>enableSubstitution</code> - Allows substitution of one object
+ * for another during serialization or deserialization.
+ * </ul>
+ *
+ * @see java.security.BasicPermission
+ *
+ * @version 0.0
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public final class SerializablePermission extends BasicPermission
+{
+
+/*
+ * Class Variables
+ */
+
+public static final String[] legal_names = { "enableSubclassImplementation",
+ "enableSubstitution" };
+/*************************************************************************/
+
+/*
+ * Constructors
+ */
+
+/**
+ * This method initializes a new instance of <code>SerializablePermission</code>
+ * that has the specified name.
+ *
+ * @param name The name of the permission.
+ *
+ * @exception IllegalArgumentException If the name is not valid for this class.
+ */
+public
+SerializablePermission(String name)
+{
+ this(name, null);
+}
+
+/*************************************************************************/
+
+/**
+ * This method initializes a new instance of <code>SerializablePermission</code>
+ * that has the specified name and action list. Note that the action list
+ * is unused in this class.
+ *
+ * @param name The name of the permission.
+ * @param actions The action list (unused).
+ *
+ * @exception IllegalArgumentException If the name is not valid for this class.
+ */
+public
+SerializablePermission(String name, String actions)
+{
+ super(name, actions);
+
+ for (int i = 0; i < legal_names.length; i++)
+ if (legal_names[i].equals(name))
+ return;
+
+ throw new IllegalArgumentException("Bad permission name: " + name);
+}
+
+
+} // class SerializablePermission
+
diff --git a/libjava/java/io/WriteAbortedException.java b/libjava/java/io/WriteAbortedException.java
new file mode 100644
index 0000000..1f22514
--- /dev/null
+++ b/libjava/java/io/WriteAbortedException.java
@@ -0,0 +1,89 @@
+/* WriteAbortedException.java -- An exception occured while writing a
+ serialization stream
+ Copyright (C) 1998 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;
+
+/**
+ * This exception is thrown when one of the other ObjectStreamException
+ * subclasses was thrown during a serialization write.
+ *
+ * @version 0.0
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class WriteAbortedException extends ObjectStreamException
+{
+
+/*
+ * Instance Variables
+ */
+
+/**
+ * The detailed exception that caused this exception to be thrown
+ */
+public Exception detail;
+private String message;
+
+/*************************************************************************/
+
+/*
+ * Constructors
+ */
+
+/**
+ * Create a new WriteAbortedException with an eof parameter indicating
+ * the detailed Exception that caused this exception to be thrown.
+ *
+ * @param detail The exception that caused this exception to be thrown
+ */
+public
+WriteAbortedException(String msg, Exception detail)
+{
+ this.message = msg;
+ this.detail = detail;
+}
+
+/*************************************************************************/
+
+/*
+ * Instance Variables
+ */
+
+/**
+ * This method returns a message indicating what went wrong, including
+ * the message text from the initial exception that caused this one to
+ * be thrown
+ */
+public String
+getMessage()
+{
+ return(message + ": " + detail.getMessage());
+}
+
+} // class WriteAbortedException
+
diff --git a/libjava/java/io/natObjectInputStream.cc b/libjava/java/io/natObjectInputStream.cc
new file mode 100644
index 0000000..b7a8dcb
--- /dev/null
+++ b/libjava/java/io/natObjectInputStream.cc
@@ -0,0 +1,78 @@
+// natObjectInputStream.cc - Native part of ObjectInputStream class.
+
+/* Copyright (C) 1998, 1999 Free Software Foundation
+
+ This ObjectInputStream is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License. Please consult the ObjectInputStream "LIBGCJ_LICENSE" for
+details. */
+
+#include <config.h>
+
+#include <gcj/cni.h>
+#include <jvm.h>
+
+#include <java/io/ObjectInputStream$GetField.h>
+#include <java/io/ObjectInputStream.h>
+#include <java/io/IOException.h>
+#include <java/lang/Class.h>
+#include <java/lang/reflect/Modifier.h>
+#include <java/lang/reflect/Method.h>
+
+jobject
+java::io::ObjectInputStream::allocateObject (jclass klass)
+{
+ jobject obj = NULL;
+ using namespace java::lang::reflect;
+
+ try
+ {
+ JvAssert (klass && ! klass->isArray ());
+ if (klass->isInterface() || Modifier::isAbstract(klass->getModifiers()))
+ obj = NULL;
+ else
+ {
+ // FIXME: will this work for String?
+ obj = JvAllocObject (klass);
+ }
+ }
+ catch (jthrowable t)
+ {
+ return NULL;
+ }
+
+ return obj;
+}
+
+
+#define ObjectClass _CL_Q34java4lang6Object
+extern java::lang::Class ObjectClass;
+#define ClassClass _CL_Q34java4lang5Class
+extern java::lang::Class ClassClass;
+
+void
+java::io::ObjectInputStream::callConstructor (jclass klass, jobject obj)
+{
+ jstring init_name = JvNewStringLatin1 ("<init>");
+ JArray<jclass> *arg_types
+ = (JArray<jclass> *) JvNewObjectArray (0, &ClassClass, NULL);
+ JArray<jobject> *args
+ = (JArray<jobject> *) JvNewObjectArray (0, &ObjectClass, NULL);
+ java::lang::reflect::Method *m = klass->getPrivateMethod (init_name, arg_types);
+ m->invoke (obj, args);
+}
+
+java::lang::reflect::Field *
+java::io::ObjectInputStream::getField (jclass klass, jstring name)
+{
+ return klass->getPrivateField (name);
+}
+
+java::lang::reflect::Method *
+java::io::ObjectInputStream::getMethod (jclass klass, jstring name,
+ JArray<jclass> *arg_types)
+{
+ return klass->getPrivateMethod (name, arg_types);
+}
+
diff --git a/libjava/java/io/natObjectOutputStream.cc b/libjava/java/io/natObjectOutputStream.cc
new file mode 100644
index 0000000..45ab753
--- /dev/null
+++ b/libjava/java/io/natObjectOutputStream.cc
@@ -0,0 +1,33 @@
+// natObjectOutputStream.cc - Native part of ObjectOutputStream class.
+
+/* Copyright (C) 1998, 1999 Free Software Foundation
+
+ This ObjectOutputStream is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License. Please consult the ObjectOutputStream "LIBGCJ_LICENSE" for
+details. */
+
+#include <config.h>
+
+#include <gcj/cni.h>
+#include <jvm.h>
+#include <java/io/ObjectOutputStream$PutField.h>
+#include <java/io/ObjectOutputStream.h>
+#include <java/io/IOException.h>
+#include <java/lang/Class.h>
+
+
+java::lang::reflect::Field *
+java::io::ObjectOutputStream::getField (jclass klass, jstring name)
+{
+ return klass->getPrivateField (name);
+}
+
+java::lang::reflect::Method *
+java::io::ObjectOutputStream::getMethod (jclass klass, jstring name,
+ JArray<jclass> *arg_types)
+{
+ return klass->getPrivateMethod (name, arg_types);
+}
+