mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			1537 lines
		
	
	
		
			46 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			1537 lines
		
	
	
		
			46 KiB
		
	
	
	
		
			Java
		
	
	
	
/* ObjectOutputStream.java -- Class used to write serialized objects
 | 
						|
   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2008
 | 
						|
   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., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
						|
02110-1301 USA.
 | 
						|
 | 
						|
Linking this library statically or dynamically with other modules is
 | 
						|
making a combined work based on this library.  Thus, the terms and
 | 
						|
conditions of the GNU General Public License cover the whole
 | 
						|
combination.
 | 
						|
 | 
						|
As a special exception, the copyright holders of this library give you
 | 
						|
permission to link this library with independent modules to produce an
 | 
						|
executable, regardless of the license terms of these independent
 | 
						|
modules, and to copy and distribute the resulting executable under
 | 
						|
terms of your choice, provided that you also meet, for each linked
 | 
						|
independent module, the terms and conditions of the license of that
 | 
						|
module.  An independent module is a module which is not derived from
 | 
						|
or based on this library.  If you modify this library, you may extend
 | 
						|
this exception to your version of the library, but you are not
 | 
						|
obligated to do so.  If you do not wish to do so, delete this
 | 
						|
exception statement from your version. */
 | 
						|
 | 
						|
 | 
						|
package java.io;
 | 
						|
 | 
						|
import gnu.java.io.ObjectIdentityMap2Int;
 | 
						|
import gnu.java.lang.reflect.TypeSignature;
 | 
						|
import gnu.java.security.action.SetAccessibleAction;
 | 
						|
 | 
						|
import java.lang.reflect.Array;
 | 
						|
import java.lang.reflect.Field;
 | 
						|
import java.lang.reflect.InvocationTargetException;
 | 
						|
import java.lang.reflect.Method;
 | 
						|
 | 
						|
import java.security.AccessController;
 | 
						|
import java.security.PrivilegedAction;
 | 
						|
 | 
						|
/**
 | 
						|
 * 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
 | 
						|
 * @author Tom Tromey (tromey@redhat.com)
 | 
						|
 * @author Jeroen Frijters (jeroen@frijters.net)
 | 
						|
 * @author Guilhem Lavaux (guilhem@kaffe.org)
 | 
						|
 * @author Michael Koch (konqueror@gmx.de)
 | 
						|
 * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
 | 
						|
 */
 | 
						|
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
 | 
						|
  {
 | 
						|
    SecurityManager secMan = System.getSecurityManager();
 | 
						|
    if (secMan != null && overridesMethods(getClass()))
 | 
						|
      secMan.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
 | 
						|
 | 
						|
    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 ObjectIdentityMap2Int();
 | 
						|
    protocolVersion = defaultProtocolVersion;
 | 
						|
    useSubclassMethod = false;
 | 
						|
    writeStreamHeader();
 | 
						|
 | 
						|
    if (DEBUG)
 | 
						|
      {
 | 
						|
        String val = System.getProperty("gcj.dumpobjects");
 | 
						|
        if (val != null && !val.equals(""))
 | 
						|
          dump = true;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * 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.
 | 
						|
   *
 | 
						|
   * @param obj the object to serialize.
 | 
						|
   * @exception NotSerializableException An attempt was made to
 | 
						|
   * serialize an <code>Object</code> that is not serializable.
 | 
						|
   *
 | 
						|
   * @exception InvalidClassException Somebody tried to serialize
 | 
						|
   * an object which is wrongly formatted.
 | 
						|
   *
 | 
						|
   * @exception IOException Exception from underlying
 | 
						|
   * <code>OutputStream</code>.
 | 
						|
   * @see #writeUnshared(Object)
 | 
						|
   */
 | 
						|
  public final void writeObject(Object obj) throws IOException
 | 
						|
  {
 | 
						|
    writeObject(obj, true);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Writes an object to the stream in the same manner as
 | 
						|
   * {@link #writeObject(Object)}, but without the use of
 | 
						|
   * references.  As a result, the object is always written
 | 
						|
   * to the stream in full.  Likewise, if an object is written
 | 
						|
   * by this method and is then later written again by
 | 
						|
   * {@link #writeObject(Object)}, both calls will write out
 | 
						|
   * the object in full, as the later call to
 | 
						|
   * {@link #writeObject(Object)} will know nothing of the
 | 
						|
   * earlier use of {@link #writeUnshared(Object)}.
 | 
						|
   *
 | 
						|
   * @param obj the object to serialize.
 | 
						|
   * @throws NotSerializableException if the object being
 | 
						|
   *                                  serialized does not implement
 | 
						|
   *                                  {@link Serializable}.
 | 
						|
   * @throws InvalidClassException if a problem occurs with
 | 
						|
   *                               the class of the object being
 | 
						|
   *                               serialized.
 | 
						|
   * @throws IOException if an I/O error occurs on the underlying
 | 
						|
   *                     <code>OutputStream</code>.
 | 
						|
   * @since 1.4
 | 
						|
   * @see #writeObject(Object)
 | 
						|
   */
 | 
						|
  public void writeUnshared(Object obj)
 | 
						|
    throws IOException
 | 
						|
  {
 | 
						|
    writeObject(obj, false);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * 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.
 | 
						|
   *
 | 
						|
   * @param obj the object to serialize.
 | 
						|
   * @param shared true if the serialized object should be
 | 
						|
   *               shared with later calls.
 | 
						|
   * @exception NotSerializableException An attempt was made to
 | 
						|
   * serialize an <code>Object</code> that is not serializable.
 | 
						|
   *
 | 
						|
   * @exception InvalidClassException Somebody tried to serialize
 | 
						|
   * an object which is wrongly formatted.
 | 
						|
   *
 | 
						|
   * @exception IOException Exception from underlying
 | 
						|
   * <code>OutputStream</code>.
 | 
						|
   * @see #writeUnshared(Object)
 | 
						|
   */
 | 
						|
  private final void writeObject(Object obj, boolean shared)
 | 
						|
    throws IOException
 | 
						|
  {
 | 
						|
    if (useSubclassMethod)
 | 
						|
      {
 | 
						|
        if (dump)
 | 
						|
          dumpElementln ("WRITE OVERRIDE: " + obj);
 | 
						|
 | 
						|
        writeObjectOverride(obj);
 | 
						|
        return;
 | 
						|
      }
 | 
						|
 | 
						|
    if (dump)
 | 
						|
      dumpElementln ("WRITE: ", obj);
 | 
						|
 | 
						|
    depth += 2;
 | 
						|
 | 
						|
    boolean was_serializing = isSerializing;
 | 
						|
    boolean old_mode = setBlockDataMode(false);
 | 
						|
    try
 | 
						|
      {
 | 
						|
        isSerializing = true;
 | 
						|
        boolean replaceDone = false;
 | 
						|
        Object replacedObject = null;
 | 
						|
 | 
						|
        while (true)
 | 
						|
          {
 | 
						|
            if (obj == null)
 | 
						|
              {
 | 
						|
                realOutput.writeByte(TC_NULL);
 | 
						|
                break;
 | 
						|
              }
 | 
						|
 | 
						|
            int handle = findHandle(obj);
 | 
						|
            if (handle >= 0 && shared)
 | 
						|
              {
 | 
						|
                realOutput.writeByte(TC_REFERENCE);
 | 
						|
                realOutput.writeInt(handle);
 | 
						|
                break;
 | 
						|
              }
 | 
						|
 | 
						|
            if (obj instanceof Class)
 | 
						|
              {
 | 
						|
                Class cl = (Class)obj;
 | 
						|
                ObjectStreamClass osc = ObjectStreamClass.lookupForClassObject(cl);
 | 
						|
                realOutput.writeByte(TC_CLASS);
 | 
						|
                if (!osc.isProxyClass)
 | 
						|
                  {
 | 
						|
                    writeObject (osc);
 | 
						|
                  }
 | 
						|
                else
 | 
						|
                  {System.err.println("1");
 | 
						|
                    realOutput.writeByte(TC_PROXYCLASSDESC);
 | 
						|
                    Class[] intfs = cl.getInterfaces();
 | 
						|
                    realOutput.writeInt(intfs.length);
 | 
						|
                    for (int i = 0; i < intfs.length; i++)
 | 
						|
                      realOutput.writeUTF(intfs[i].getName());
 | 
						|
 | 
						|
                    boolean oldmode = setBlockDataMode(true);
 | 
						|
                    annotateProxyClass(cl);
 | 
						|
                    setBlockDataMode(oldmode);
 | 
						|
                    realOutput.writeByte(TC_ENDBLOCKDATA);
 | 
						|
 | 
						|
                    writeObject(osc.getSuper());
 | 
						|
                  }
 | 
						|
                if (shared)
 | 
						|
                  assignNewHandle(obj);
 | 
						|
                break;
 | 
						|
              }
 | 
						|
 | 
						|
            if (obj instanceof ObjectStreamClass)
 | 
						|
              {
 | 
						|
                writeClassDescriptor((ObjectStreamClass) obj);
 | 
						|
                break;
 | 
						|
              }
 | 
						|
 | 
						|
            Class clazz = obj.getClass();
 | 
						|
            ObjectStreamClass osc = ObjectStreamClass.lookupForClassObject(clazz);
 | 
						|
            if (osc == null)
 | 
						|
              throw new NotSerializableException(clazz.getName());
 | 
						|
 | 
						|
            if (osc.isEnum())
 | 
						|
              {
 | 
						|
                /* TC_ENUM classDesc newHandle enumConstantName */
 | 
						|
                realOutput.writeByte(TC_ENUM);
 | 
						|
                writeObject(osc);
 | 
						|
                if (shared)
 | 
						|
                  assignNewHandle(obj);
 | 
						|
                writeObject(((Enum) obj).name());
 | 
						|
                break;
 | 
						|
              }
 | 
						|
 | 
						|
            if ((replacementEnabled || obj instanceof Serializable)
 | 
						|
                && ! replaceDone)
 | 
						|
              {
 | 
						|
                replacedObject = obj;
 | 
						|
 | 
						|
                if (obj instanceof Serializable)
 | 
						|
                  {
 | 
						|
                    try
 | 
						|
                      {
 | 
						|
                        Method m = osc.writeReplaceMethod;
 | 
						|
                        if (m != null)
 | 
						|
                            obj = m.invoke(obj, new Object[0]);
 | 
						|
                      }
 | 
						|
                    catch (IllegalAccessException ignore)
 | 
						|
                      {
 | 
						|
                      }
 | 
						|
                    catch (InvocationTargetException ignore)
 | 
						|
                      {
 | 
						|
                      }
 | 
						|
                  }
 | 
						|
 | 
						|
                if (replacementEnabled)
 | 
						|
                  obj = replaceObject(obj);
 | 
						|
 | 
						|
                replaceDone = true;
 | 
						|
                continue;
 | 
						|
              }
 | 
						|
 | 
						|
            if (obj instanceof String)
 | 
						|
              {
 | 
						|
                String s = (String)obj;
 | 
						|
                long l = realOutput.getUTFlength(s, 0, 0);
 | 
						|
                if (l <= 65535)
 | 
						|
                  {
 | 
						|
                    realOutput.writeByte(TC_STRING);
 | 
						|
                    if (shared)
 | 
						|
                      assignNewHandle(obj);
 | 
						|
                    realOutput.writeUTFShort(s, (int)l);
 | 
						|
                  }
 | 
						|
                else
 | 
						|
                  {
 | 
						|
                    realOutput.writeByte(TC_LONGSTRING);
 | 
						|
                    if (shared)
 | 
						|
                      assignNewHandle(obj);
 | 
						|
                    realOutput.writeUTFLong(s, l);
 | 
						|
                  }
 | 
						|
                break;
 | 
						|
              }
 | 
						|
 | 
						|
            if (clazz.isArray ())
 | 
						|
              {
 | 
						|
                realOutput.writeByte(TC_ARRAY);
 | 
						|
                writeObject(osc);
 | 
						|
                if (shared)
 | 
						|
                  assignNewHandle(obj);
 | 
						|
                writeArraySizeAndElements(obj, clazz.getComponentType());
 | 
						|
                break;
 | 
						|
              }
 | 
						|
 | 
						|
            realOutput.writeByte(TC_OBJECT);
 | 
						|
            writeObject(osc);
 | 
						|
 | 
						|
            if (shared)
 | 
						|
              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);
 | 
						|
                    realOutput.writeByte(TC_ENDBLOCKDATA);
 | 
						|
                  }
 | 
						|
 | 
						|
                break;
 | 
						|
              }
 | 
						|
 | 
						|
            if (obj instanceof Serializable)
 | 
						|
              {
 | 
						|
                Object prevObject = this.currentObject;
 | 
						|
                ObjectStreamClass prevObjectStreamClass = this.currentObjectStreamClass;
 | 
						|
                currentObject = obj;
 | 
						|
                ObjectStreamClass[] hierarchy = osc.hierarchy();
 | 
						|
 | 
						|
                for (int i = 0; i < hierarchy.length; i++)
 | 
						|
                  {
 | 
						|
                    currentObjectStreamClass = hierarchy[i];
 | 
						|
 | 
						|
                    fieldsAlreadyWritten = false;
 | 
						|
                    if (currentObjectStreamClass.hasWriteMethod())
 | 
						|
                      {
 | 
						|
                        if (dump)
 | 
						|
                          dumpElementln ("WRITE METHOD CALLED FOR: ", obj);
 | 
						|
                        setBlockDataMode(true);
 | 
						|
                        callWriteMethod(obj, currentObjectStreamClass);
 | 
						|
                        setBlockDataMode(false);
 | 
						|
                        realOutput.writeByte(TC_ENDBLOCKDATA);
 | 
						|
                        if (dump)
 | 
						|
                          dumpElementln ("WRITE ENDBLOCKDATA FOR: ", obj);
 | 
						|
                      }
 | 
						|
                    else
 | 
						|
                      {
 | 
						|
                        if (dump)
 | 
						|
                          dumpElementln ("WRITE FIELDS CALLED FOR: ", obj);
 | 
						|
                        writeFields(obj, currentObjectStreamClass);
 | 
						|
                      }
 | 
						|
                  }
 | 
						|
 | 
						|
                this.currentObject = prevObject;
 | 
						|
                this.currentObjectStreamClass = prevObjectStreamClass;
 | 
						|
                currentPutField = null;
 | 
						|
                break;
 | 
						|
              }
 | 
						|
 | 
						|
            throw new NotSerializableException(clazz.getName()
 | 
						|
                                               + " in "
 | 
						|
                                               + obj.getClass());
 | 
						|
          } // end pseudo-loop
 | 
						|
      }
 | 
						|
    catch (ObjectStreamException ose)
 | 
						|
      {
 | 
						|
        // Rethrow these are fatal.
 | 
						|
        throw ose;
 | 
						|
      }
 | 
						|
    catch (IOException e)
 | 
						|
      {
 | 
						|
        realOutput.writeByte(TC_EXCEPTION);
 | 
						|
        reset(true);
 | 
						|
 | 
						|
        setBlockDataMode(false);
 | 
						|
        try
 | 
						|
          {
 | 
						|
            if (DEBUG)
 | 
						|
              {
 | 
						|
                e.printStackTrace(System.out);
 | 
						|
              }
 | 
						|
            writeObject(e);
 | 
						|
          }
 | 
						|
        catch (IOException ioe)
 | 
						|
          {
 | 
						|
            StreamCorruptedException ex =
 | 
						|
              new StreamCorruptedException
 | 
						|
              (ioe + " thrown while exception was being written to stream.");
 | 
						|
            if (DEBUG)
 | 
						|
              {
 | 
						|
                ex.printStackTrace(System.out);
 | 
						|
              }
 | 
						|
            throw ex;
 | 
						|
          }
 | 
						|
 | 
						|
        reset (true);
 | 
						|
 | 
						|
      }
 | 
						|
    finally
 | 
						|
      {
 | 
						|
        isSerializing = was_serializing;
 | 
						|
        setBlockDataMode(old_mode);
 | 
						|
        depth -= 2;
 | 
						|
 | 
						|
        if (dump)
 | 
						|
          dumpElementln ("END: ", obj);
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  protected void writeClassDescriptor(ObjectStreamClass osc) throws IOException
 | 
						|
  {
 | 
						|
    if (osc.isProxyClass)
 | 
						|
      {
 | 
						|
        realOutput.writeByte(TC_PROXYCLASSDESC);
 | 
						|
        Class[] intfs = osc.forClass().getInterfaces();
 | 
						|
        realOutput.writeInt(intfs.length);
 | 
						|
        for (int i = 0; i < intfs.length; i++)
 | 
						|
          realOutput.writeUTF(intfs[i].getName());
 | 
						|
 | 
						|
        assignNewHandle(osc);
 | 
						|
 | 
						|
        boolean oldmode = setBlockDataMode(true);
 | 
						|
        annotateProxyClass(osc.forClass());
 | 
						|
        setBlockDataMode(oldmode);
 | 
						|
        realOutput.writeByte(TC_ENDBLOCKDATA);
 | 
						|
      }
 | 
						|
    else
 | 
						|
      {
 | 
						|
        realOutput.writeByte(TC_CLASSDESC);
 | 
						|
        realOutput.writeUTF(osc.getName());
 | 
						|
        if (osc.isEnum())
 | 
						|
          realOutput.writeLong(0L);
 | 
						|
        else
 | 
						|
          realOutput.writeLong(osc.getSerialVersionUID());
 | 
						|
        assignNewHandle(osc);
 | 
						|
 | 
						|
        int flags = osc.getFlags();
 | 
						|
 | 
						|
        if (protocolVersion == PROTOCOL_VERSION_2
 | 
						|
            && osc.isExternalizable())
 | 
						|
        flags |= SC_BLOCK_DATA;
 | 
						|
 | 
						|
        realOutput.writeByte(flags);
 | 
						|
 | 
						|
        ObjectStreamField[] fields = osc.fields;
 | 
						|
 | 
						|
        if (fields == ObjectStreamClass.INVALID_FIELDS)
 | 
						|
          throw new InvalidClassException
 | 
						|
                  (osc.getName(), "serialPersistentFields is invalid");
 | 
						|
 | 
						|
        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());
 | 
						|
          }
 | 
						|
 | 
						|
        boolean oldmode = setBlockDataMode(true);
 | 
						|
        annotateClass(osc.forClass());
 | 
						|
        setBlockDataMode(oldmode);
 | 
						|
        realOutput.writeByte(TC_ENDBLOCKDATA);
 | 
						|
      }
 | 
						|
 | 
						|
    if (osc.isSerializable() || osc.isExternalizable())
 | 
						|
      writeObject(osc.getSuper());
 | 
						|
    else
 | 
						|
      writeObject(null);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * 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);
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  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 writeFields 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_2</code> by default, as is done
 | 
						|
   * since the JDK 1.2.
 | 
						|
   * <p>
 | 
						|
   * For an explanation of the differences between the two protocols
 | 
						|
   * see the Java Object Serialization Specification.
 | 
						|
   * </p>
 | 
						|
   *
 | 
						|
   * @param version the version to use.
 | 
						|
   *
 | 
						|
   * @throws IllegalArgumentException if <code>version</code> is not a valid
 | 
						|
   * protocol.
 | 
						|
   * @throws IllegalStateException if called after the first the first object
 | 
						|
   * was serialized.
 | 
						|
   * @throws IOException if an I/O error occurs.
 | 
						|
   *
 | 
						|
   * @see ObjectStreamConstants#PROTOCOL_VERSION_1
 | 
						|
   * @see ObjectStreamConstants#PROTOCOL_VERSION_2
 | 
						|
   *
 | 
						|
   * @since 1.2
 | 
						|
   */
 | 
						|
  public void useProtocolVersion(int version) throws IOException
 | 
						|
  {
 | 
						|
    if (version != PROTOCOL_VERSION_1 && version != PROTOCOL_VERSION_2)
 | 
						|
      throw new IllegalArgumentException("Invalid protocol version requested.");
 | 
						|
 | 
						|
    if (nextOID != baseWireHandle)
 | 
						|
      throw new IllegalStateException("Protocol version cannot be changed "
 | 
						|
                                      + "after serialization started.");
 | 
						|
 | 
						|
    protocolVersion = 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 ObjectInputStream#resolveClass(java.io.ObjectStreamClass)
 | 
						|
   */
 | 
						|
  protected void annotateClass(Class<?> cl) throws IOException
 | 
						|
  {
 | 
						|
  }
 | 
						|
 | 
						|
  protected void annotateProxyClass(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)
 | 
						|
      {
 | 
						|
        SecurityManager sm = System.getSecurityManager();
 | 
						|
        if (sm != null)
 | 
						|
          sm.checkPermission(new SerializablePermission("enableSubstitution"));
 | 
						|
      }
 | 
						|
 | 
						|
    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 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 DataOutputStream#write(byte[])
 | 
						|
   */
 | 
						|
  public void write(byte[] b) throws IOException
 | 
						|
  {
 | 
						|
    write(b, 0, b.length);
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  /**
 | 
						|
   * @see 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 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;
 | 
						|
 | 
						|
    if (writeDataAsBlocks)
 | 
						|
      writeBlockDataHeader(blockDataCount);
 | 
						|
    realOutput.write(blockData, 0, blockDataCount);
 | 
						|
    blockDataCount = 0;
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  /**
 | 
						|
   * @see java.io.DataOutputStream#close ()
 | 
						|
   */
 | 
						|
  public void close() throws IOException
 | 
						|
  {
 | 
						|
    flush();
 | 
						|
    realOutput.close();
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  /**
 | 
						|
   * @see java.io.DataOutputStream#writeBoolean (boolean)
 | 
						|
   */
 | 
						|
  public void writeBoolean(boolean data) throws IOException
 | 
						|
  {
 | 
						|
    blockDataOutput.writeBoolean(data);
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  /**
 | 
						|
   * @see java.io.DataOutputStream#writeByte (int)
 | 
						|
   */
 | 
						|
  public void writeByte(int data) throws IOException
 | 
						|
  {
 | 
						|
    blockDataOutput.writeByte(data);
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  /**
 | 
						|
   * @see java.io.DataOutputStream#writeShort (int)
 | 
						|
   */
 | 
						|
  public void writeShort (int data) throws IOException
 | 
						|
  {
 | 
						|
    blockDataOutput.writeShort(data);
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  /**
 | 
						|
   * @see java.io.DataOutputStream#writeChar (int)
 | 
						|
   */
 | 
						|
  public void writeChar(int data) throws IOException
 | 
						|
  {
 | 
						|
    blockDataOutput.writeChar(data);
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  /**
 | 
						|
   * @see java.io.DataOutputStream#writeInt (int)
 | 
						|
   */
 | 
						|
  public void writeInt(int data) throws IOException
 | 
						|
  {
 | 
						|
    blockDataOutput.writeInt(data);
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  /**
 | 
						|
   * @see java.io.DataOutputStream#writeLong (long)
 | 
						|
   */
 | 
						|
  public void writeLong(long data) throws IOException
 | 
						|
  {
 | 
						|
    blockDataOutput.writeLong(data);
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  /**
 | 
						|
   * @see java.io.DataOutputStream#writeFloat (float)
 | 
						|
   */
 | 
						|
  public void writeFloat(float data) throws IOException
 | 
						|
  {
 | 
						|
    blockDataOutput.writeFloat(data);
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  /**
 | 
						|
   * @see java.io.DataOutputStream#writeDouble (double)
 | 
						|
   */
 | 
						|
  public void writeDouble(double data) throws IOException
 | 
						|
  {
 | 
						|
    blockDataOutput.writeDouble(data);
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  /**
 | 
						|
   * @see java.io.DataOutputStream#writeBytes (java.lang.String)
 | 
						|
   */
 | 
						|
  public void writeBytes(String data) throws IOException
 | 
						|
  {
 | 
						|
    blockDataOutput.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 abstract static class PutField
 | 
						|
  {
 | 
						|
    public abstract void put (String name, boolean value);
 | 
						|
    public abstract void put (String name, byte value);
 | 
						|
    public abstract void put (String name, char value);
 | 
						|
    public abstract void put (String name, double value);
 | 
						|
    public abstract void put (String name, float value);
 | 
						|
    public abstract void put (String name, int value);
 | 
						|
    public abstract void put (String name, long value);
 | 
						|
    public abstract void put (String name, short value);
 | 
						|
    public abstract void put (String name, Object value);
 | 
						|
 | 
						|
    /**
 | 
						|
     * @deprecated
 | 
						|
     */
 | 
						|
    public abstract void write (ObjectOutput out) throws IOException;
 | 
						|
  }
 | 
						|
 | 
						|
  public PutField putFields() throws IOException
 | 
						|
  {
 | 
						|
    if (currentPutField != null)
 | 
						|
      return currentPutField;
 | 
						|
 | 
						|
    currentPutField = new PutField()
 | 
						|
      {
 | 
						|
        private byte[] prim_field_data
 | 
						|
          = new byte[currentObjectStreamClass.primFieldSize];
 | 
						|
        private Object[] objs
 | 
						|
          = new Object[currentObjectStreamClass.objectFieldCount];
 | 
						|
 | 
						|
        private ObjectStreamField getField (String name)
 | 
						|
        {
 | 
						|
          ObjectStreamField field
 | 
						|
            = currentObjectStreamClass.getField(name);
 | 
						|
 | 
						|
          if (field == null)
 | 
						|
            throw new IllegalArgumentException("no such serializable field " + name);
 | 
						|
 | 
						|
          return field;
 | 
						|
        }
 | 
						|
 | 
						|
        public void put(String name, boolean value)
 | 
						|
        {
 | 
						|
          ObjectStreamField field = getField(name);
 | 
						|
 | 
						|
          checkType(field, 'Z');
 | 
						|
          prim_field_data[field.getOffset ()] = (byte)(value ? 1 : 0);
 | 
						|
        }
 | 
						|
 | 
						|
        public void put(String name, byte value)
 | 
						|
        {
 | 
						|
          ObjectStreamField field = getField(name);
 | 
						|
 | 
						|
          checkType(field, 'B');
 | 
						|
          prim_field_data[field.getOffset()] = value;
 | 
						|
        }
 | 
						|
 | 
						|
        public void put(String name, char value)
 | 
						|
        {
 | 
						|
          ObjectStreamField field = 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)
 | 
						|
        {
 | 
						|
          ObjectStreamField field = 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)
 | 
						|
        {
 | 
						|
          ObjectStreamField field = 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)
 | 
						|
        {
 | 
						|
          ObjectStreamField field = 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)
 | 
						|
        {
 | 
						|
          ObjectStreamField field = 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)
 | 
						|
        {
 | 
						|
          ObjectStreamField field = 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)
 | 
						|
        {
 | 
						|
          ObjectStreamField field = getField(name);
 | 
						|
 | 
						|
          if (value != null &&
 | 
						|
              ! field.getType().isAssignableFrom(value.getClass ()))
 | 
						|
            throw new IllegalArgumentException("Class " + value.getClass() +
 | 
						|
                                               " cannot be cast to " + field.getType());
 | 
						|
          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.
 | 
						|
          boolean oldmode = setBlockDataMode(false);
 | 
						|
          out.write(prim_field_data);
 | 
						|
          for (int i = 0; i < objs.length; ++ i)
 | 
						|
            out.writeObject(objs[i]);
 | 
						|
          setBlockDataMode(oldmode);
 | 
						|
        }
 | 
						|
 | 
						|
        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");
 | 
						|
 | 
						|
    markFieldsWritten();
 | 
						|
    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 int findHandle(Object obj)
 | 
						|
  {
 | 
						|
    return OIDLookupTable.get(obj);
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  // assigns the next availible handle to OBJ
 | 
						|
  private int assignNewHandle(Object obj)
 | 
						|
  {
 | 
						|
    OIDLookupTable.put(obj, 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);
 | 
						|
            realOutput.write(cast_array, 0, length);
 | 
						|
            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]);
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
/* GCJ LOCAL */
 | 
						|
  // writes out FIELDS of OBJECT for the specified ObjectStreamClass.
 | 
						|
  // FIELDS are already supposed already to be in canonical order, but
 | 
						|
  // under some circumstances (to do with Proxies) this isn't the
 | 
						|
  // case, so we call ensureFieldsSet().
 | 
						|
  private void writeFields(Object obj, ObjectStreamClass osc)
 | 
						|
    throws IOException
 | 
						|
  {
 | 
						|
    osc.ensureFieldsSet(osc.forClass());
 | 
						|
/* END GCJ LOCAL */
 | 
						|
 | 
						|
    ObjectStreamField[] fields = osc.fields;
 | 
						|
    boolean oldmode = setBlockDataMode(false);
 | 
						|
 | 
						|
    try
 | 
						|
      {
 | 
						|
        writeFields(obj,fields);
 | 
						|
      }
 | 
						|
    catch (IllegalArgumentException _)
 | 
						|
      {
 | 
						|
        InvalidClassException e = new InvalidClassException
 | 
						|
          ("writing fields of class " + osc.forClass().getName());
 | 
						|
        e.initCause(_);
 | 
						|
        throw e;
 | 
						|
      }
 | 
						|
    catch (IOException e)
 | 
						|
      {
 | 
						|
        throw e;
 | 
						|
      }
 | 
						|
    catch (Exception _)
 | 
						|
      {
 | 
						|
        IOException e = new IOException("Unexpected exception " + _);
 | 
						|
        e.initCause(_);
 | 
						|
        throw(e);
 | 
						|
      }
 | 
						|
 | 
						|
    setBlockDataMode(oldmode);
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  /**
 | 
						|
   * Helper function for writeFields(Object,ObjectStreamClass): write
 | 
						|
   * fields from given fields array.  Pass exception on.
 | 
						|
   *
 | 
						|
   * @param obj the object to be written
 | 
						|
   *
 | 
						|
   * @param fields the fields of obj to be written.
 | 
						|
   */
 | 
						|
  private void writeFields(Object obj, ObjectStreamField[] fields)
 | 
						|
    throws
 | 
						|
      IllegalArgumentException, IllegalAccessException, IOException
 | 
						|
  {
 | 
						|
    for (int i = 0; i < fields.length; i++)
 | 
						|
      {
 | 
						|
        ObjectStreamField osf = fields[i];
 | 
						|
        Field field = osf.field;
 | 
						|
 | 
						|
        if (DEBUG && dump)
 | 
						|
          dumpElementln ("WRITE FIELD: " + osf.getName() + " type=" + osf.getType());
 | 
						|
 | 
						|
        switch (osf.getTypeCode())
 | 
						|
          {
 | 
						|
          case 'Z': realOutput.writeBoolean(field.getBoolean(obj)); break;
 | 
						|
          case 'B': realOutput.writeByte   (field.getByte   (obj)); break;
 | 
						|
          case 'S': realOutput.writeShort  (field.getShort  (obj)); break;
 | 
						|
          case 'C': realOutput.writeChar   (field.getChar   (obj)); break;
 | 
						|
          case 'I': realOutput.writeInt    (field.getInt    (obj)); break;
 | 
						|
          case 'F': realOutput.writeFloat  (field.getFloat  (obj)); break;
 | 
						|
          case 'J': realOutput.writeLong   (field.getLong   (obj)); break;
 | 
						|
          case 'D': realOutput.writeDouble (field.getDouble (obj)); break;
 | 
						|
          case 'L':
 | 
						|
          case '[':            writeObject (field.get       (obj)); break;
 | 
						|
          default:
 | 
						|
            throw new IOException("Unexpected type code " + osf.getTypeCode());
 | 
						|
          }
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  // Toggles writing primitive data to block-data buffer.
 | 
						|
  // Package-private to avoid a trampoline constructor.
 | 
						|
  boolean setBlockDataMode(boolean on) throws IOException
 | 
						|
  {
 | 
						|
    if (on == writeDataAsBlocks)
 | 
						|
      return on;
 | 
						|
 | 
						|
    drain();
 | 
						|
    boolean oldmode = writeDataAsBlocks;
 | 
						|
    writeDataAsBlocks = on;
 | 
						|
 | 
						|
    if (on)
 | 
						|
      dataOutput = blockDataOutput;
 | 
						|
    else
 | 
						|
      dataOutput = realOutput;
 | 
						|
 | 
						|
    return oldmode;
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  private void callWriteMethod(Object obj, ObjectStreamClass osc)
 | 
						|
    throws IOException
 | 
						|
  {
 | 
						|
    currentPutField = null;
 | 
						|
    try
 | 
						|
      {
 | 
						|
        Object args[] = {this};
 | 
						|
        osc.writeObjectMethod.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;
 | 
						|
 | 
						|
        IOException ioe
 | 
						|
          = new IOException("Exception thrown from writeObject() on " +
 | 
						|
                            osc.forClass().getName() + ": " +
 | 
						|
                            exception.getClass().getName());
 | 
						|
        ioe.initCause(exception);
 | 
						|
        throw ioe;
 | 
						|
      }
 | 
						|
    catch (Exception x)
 | 
						|
      {
 | 
						|
        IOException ioe
 | 
						|
          = new IOException("Failure invoking writeObject() on " +
 | 
						|
                            osc.forClass().getName() + ": " +
 | 
						|
                            x.getClass().getName());
 | 
						|
        ioe.initCause(x);
 | 
						|
        throw ioe;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  private void dumpElementln (String msg, Object obj)
 | 
						|
  {
 | 
						|
    try
 | 
						|
      {
 | 
						|
        for (int i = 0; i < depth; i++)
 | 
						|
          System.out.print (" ");
 | 
						|
        System.out.print (Thread.currentThread() + ": ");
 | 
						|
        System.out.print (msg);
 | 
						|
        if (java.lang.reflect.Proxy.isProxyClass(obj.getClass()))
 | 
						|
          System.out.print (obj.getClass());
 | 
						|
        else
 | 
						|
          System.out.print (obj);
 | 
						|
      }
 | 
						|
    catch (Exception _)
 | 
						|
      {
 | 
						|
      }
 | 
						|
    finally
 | 
						|
      {
 | 
						|
        System.out.println ();
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  private void dumpElementln (String msg)
 | 
						|
  {
 | 
						|
    for (int i = 0; i < depth; i++)
 | 
						|
      System.out.print (" ");
 | 
						|
    System.out.print (Thread.currentThread() + ": ");
 | 
						|
    System.out.println(msg);
 | 
						|
  }
 | 
						|
 | 
						|
  // this value comes from 1.2 spec, but is used in 1.1 as well
 | 
						|
  private static final int BUFFER_SIZE = 1024;
 | 
						|
 | 
						|
  private static int defaultProtocolVersion = PROTOCOL_VERSION_2;
 | 
						|
 | 
						|
  private DataOutputStream dataOutput;
 | 
						|
  private boolean writeDataAsBlocks;
 | 
						|
  private DataOutputStream realOutput;
 | 
						|
  private DataOutputStream blockDataOutput;
 | 
						|
  private byte[] blockData;
 | 
						|
  private int blockDataCount;
 | 
						|
  private Object currentObject;
 | 
						|
  // Package-private to avoid a trampoline.
 | 
						|
  ObjectStreamClass currentObjectStreamClass;
 | 
						|
  private PutField currentPutField;
 | 
						|
  private boolean fieldsAlreadyWritten;
 | 
						|
  private boolean replacementEnabled;
 | 
						|
  private boolean isSerializing;
 | 
						|
  private int nextOID;
 | 
						|
  private ObjectIdentityMap2Int OIDLookupTable;
 | 
						|
  private int protocolVersion;
 | 
						|
  private boolean useSubclassMethod;
 | 
						|
  private SetAccessibleAction setAccessible = new SetAccessibleAction();
 | 
						|
 | 
						|
  // The nesting depth for debugging output
 | 
						|
  private int depth = 0;
 | 
						|
 | 
						|
  // Set if we're generating debugging dumps
 | 
						|
  private boolean dump = false;
 | 
						|
 | 
						|
  private static final boolean DEBUG = false;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns true if the given class overrides either of the
 | 
						|
   * methods <code>putFields</code> or <code>writeUnshared</code>.
 | 
						|
   *
 | 
						|
   * @param clazz the class to check.
 | 
						|
   * @return true if the class overrides one of the methods.
 | 
						|
   */
 | 
						|
  private static boolean overridesMethods(final Class<?> clazz)
 | 
						|
  {
 | 
						|
    if (clazz == ObjectOutputStream.class)
 | 
						|
      return false;
 | 
						|
 | 
						|
    return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
 | 
						|
        public Boolean run()
 | 
						|
        {
 | 
						|
          Method[] methods = clazz.getDeclaredMethods();
 | 
						|
          for (int a = 0; a < methods.length; ++a)
 | 
						|
            {
 | 
						|
              String name = methods[a].getName();
 | 
						|
              if (name.equals("writeUnshared"))
 | 
						|
                {
 | 
						|
                  Class<?>[] paramTypes = methods[a].getParameterTypes();
 | 
						|
                  if (paramTypes.length == 1 &&
 | 
						|
                      paramTypes[0] == Object.class &&
 | 
						|
                      methods[a].getReturnType() == Void.class)
 | 
						|
                    return true;
 | 
						|
                }
 | 
						|
              else if (name.equals("putFields"))
 | 
						|
                {
 | 
						|
                  if (methods[a].getParameterTypes().length == 0 &&
 | 
						|
                      methods[a].getReturnType() == PutField.class)
 | 
						|
                    return true;
 | 
						|
                }
 | 
						|
            }
 | 
						|
          return false;
 | 
						|
        }
 | 
						|
      });
 | 
						|
  }
 | 
						|
 | 
						|
}
 |