mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			1372 lines
		
	
	
		
			36 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			1372 lines
		
	
	
		
			36 KiB
		
	
	
	
		
			Java
		
	
	
	
/* ObjectOutputStream.java -- Class used to write serialized objects
 | 
						|
   Copyright (C) 1998, 1999, 2000 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.lang.reflect.InvocationTargetException;
 | 
						|
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<type></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, they 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,
 | 
						|
     they 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 Serializable)
 | 
						|
	    && ! replaceDone)
 | 
						|
	{
 | 
						|
	  replacedObject = obj;
 | 
						|
 | 
						|
	  if (obj instanceof Serializable)
 | 
						|
	    {
 | 
						|
	      Method m = null;
 | 
						|
	      try
 | 
						|
	      {
 | 
						|
	        Class classArgs[] = {};
 | 
						|
		m = obj.getClass ().getDeclaredMethod ("writeReplace",
 | 
						|
						       classArgs);
 | 
						|
		// m can't be null by definition since an exception would
 | 
						|
		// have been thrown so a check for null is not needed.
 | 
						|
		obj = m.invoke (obj, new Object[] {});
 | 
						|
	      }
 | 
						|
	      catch (NoSuchMethodException ignore)
 | 
						|
	      {
 | 
						|
	      }
 | 
						|
	      catch (IllegalAccessException ignore)
 | 
						|
	      {
 | 
						|
	      }
 | 
						|
	      catch (InvocationTargetException ignore)
 | 
						|
	      {
 | 
						|
	      }
 | 
						|
	    }
 | 
						|
 | 
						|
	  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 (clazz.getName ());
 | 
						|
 | 
						|
	if (clazz.isArray ())
 | 
						|
	{
 | 
						|
	  realOutput.writeByte (TC_ARRAY);
 | 
						|
	  writeObject (osc);
 | 
						|
	  assignNewHandle (obj);
 | 
						|
	  writeArraySizeAndElements (obj, clazz.getComponentType ());
 | 
						|
	  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];
 | 
						|
 | 
						|
	    fieldsAlreadyWritten = false;
 | 
						|
	    has_write = currentObjectStreamClass.hasWriteMethod ();
 | 
						|
 | 
						|
	    writeFields (obj, currentObjectStreamClass.fields,
 | 
						|
			 has_write);
 | 
						|
 | 
						|
	    if (has_write)
 | 
						|
	    {
 | 
						|
	      drain ();
 | 
						|
	      realOutput.writeByte (TC_ENDBLOCKDATA);
 | 
						|
	    }
 | 
						|
	  }
 | 
						|
 | 
						|
	  currentObject = null;
 | 
						|
	  currentObjectStreamClass = null;
 | 
						|
	  currentPutField = null;
 | 
						|
	  break;
 | 
						|
	}
 | 
						|
 | 
						|
	throw new NotSerializableException (clazz.getName ());
 | 
						|
      } // 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 defaultWriteObject 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, 'C');
 | 
						|
	    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, 'D');
 | 
						|
	    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, 'F');
 | 
						|
	    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, 'I');
 | 
						|
	    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, 'J');
 | 
						|
	    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, 'S');
 | 
						|
	    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 (value != null &&
 | 
						|
	    	! field.getType ().isAssignableFrom (value.getClass ()))
 | 
						|
	      throw new IllegalArgumentException ();
 | 
						|
	    objs[field.getOffset ()] = value;
 | 
						|
	  }
 | 
						|
 | 
						|
	public void write (ObjectOutput out) throws IOException
 | 
						|
	  {
 | 
						|
	    // Apparently Block data is not used with PutField as per
 | 
						|
	    // empirical evidence against JDK 1.2.  Also see Mauve test
 | 
						|
	    // java.io.ObjectInputOutput.Test.GetPutField.
 | 
						|
	    setBlockDataMode (false);
 | 
						|
	    out.write (prim_field_data);
 | 
						|
	    for (int i = 0; i < objs.length; ++ i)
 | 
						|
	      out.writeObject (objs[i]);
 | 
						|
	    setBlockDataMode (true);
 | 
						|
	  }
 | 
						|
 | 
						|
	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
 | 
						|
  {
 | 
						|
    Class klass = obj.getClass ();
 | 
						|
    try
 | 
						|
      {
 | 
						|
	Class classArgs[] = {ObjectOutputStream.class};
 | 
						|
	Method m = getMethod (klass, "writeObject", classArgs);
 | 
						|
	if (m == null)
 | 
						|
	  return;
 | 
						|
	Object args[] = {this};
 | 
						|
	m.invoke (obj, args);	
 | 
						|
      }
 | 
						|
    catch (InvocationTargetException x)
 | 
						|
      {
 | 
						|
        /* Rethrow if possible. */
 | 
						|
	Throwable exception = x.getTargetException();
 | 
						|
	if (exception instanceof RuntimeException)
 | 
						|
	  throw (RuntimeException) exception;
 | 
						|
	if (exception instanceof IOException)
 | 
						|
	  throw (IOException) exception;
 | 
						|
 | 
						|
	throw new IOException ("Exception thrown from writeObject() on " +
 | 
						|
			       klass + ": " + exception.getClass().getName());
 | 
						|
      }
 | 
						|
    catch (Exception x)
 | 
						|
      {
 | 
						|
	throw new IOException ("Failure invoking writeObject() on " +
 | 
						|
			       klass + ": " + x.getClass().getName());
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  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;
 | 
						|
}
 |