mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			2144 lines
		
	
	
		
			70 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			2144 lines
		
	
	
		
			70 KiB
		
	
	
	
		
			Java
		
	
	
	
/* ObjectInputStream.java -- Class used to read serialized objects
 | 
						|
   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 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.classpath.Pair;
 | 
						|
import gnu.classpath.VMStackWalker;
 | 
						|
 | 
						|
import java.lang.reflect.Array;
 | 
						|
import java.lang.reflect.Constructor;
 | 
						|
import java.lang.reflect.Field;
 | 
						|
import java.lang.reflect.InvocationTargetException;
 | 
						|
import java.lang.reflect.Method;
 | 
						|
import java.lang.reflect.Modifier;
 | 
						|
import java.lang.reflect.Proxy;
 | 
						|
import java.security.AccessController;
 | 
						|
import java.security.PrivilegedAction;
 | 
						|
import java.util.HashMap;
 | 
						|
import java.util.Hashtable;
 | 
						|
import java.util.Iterator;
 | 
						|
import java.util.Map;
 | 
						|
import java.util.TreeSet;
 | 
						|
 | 
						|
/**
 | 
						|
 * @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 ObjectInputStream extends InputStream
 | 
						|
  implements ObjectInput, ObjectStreamConstants
 | 
						|
{
 | 
						|
  /**
 | 
						|
   * Creates a new <code>ObjectInputStream</code> that will do all of
 | 
						|
   * its reading from <code>in</code>.  This method also checks
 | 
						|
   * the stream by reading the header information (stream magic number
 | 
						|
   * and stream version).
 | 
						|
   *
 | 
						|
   * @exception IOException Reading stream header from underlying
 | 
						|
   * stream cannot be completed.
 | 
						|
   *
 | 
						|
   * @exception StreamCorruptedException An invalid stream magic
 | 
						|
   * number or stream version was read from the stream.
 | 
						|
   *
 | 
						|
   * @see #readStreamHeader()
 | 
						|
   */
 | 
						|
  public ObjectInputStream(InputStream in)
 | 
						|
    throws IOException, StreamCorruptedException
 | 
						|
  {
 | 
						|
    if (DEBUG)
 | 
						|
      {
 | 
						|
        String val = System.getProperty("gcj.dumpobjects");
 | 
						|
        if (dump == false && val != null && !val.equals(""))
 | 
						|
          {
 | 
						|
            dump = true;
 | 
						|
            System.out.println ("Serialization debugging enabled");
 | 
						|
          }
 | 
						|
        else if (dump == true && (val == null || val.equals("")))
 | 
						|
          {
 | 
						|
            dump = false;
 | 
						|
            System.out.println ("Serialization debugging disabled");
 | 
						|
          }
 | 
						|
      }
 | 
						|
 | 
						|
    this.resolveEnabled = false;
 | 
						|
    this.blockDataPosition = 0;
 | 
						|
    this.blockDataBytes = 0;
 | 
						|
    this.blockData = new byte[BUFFER_SIZE];
 | 
						|
    this.blockDataInput = new DataInputStream(this);
 | 
						|
    this.realInputStream = new DataInputStream(in);
 | 
						|
    this.nextOID = baseWireHandle;
 | 
						|
    handles = new HashMap<Integer,Pair<Boolean,Object>>();
 | 
						|
    this.classLookupTable = new Hashtable<Class,ObjectStreamClass>();
 | 
						|
    setBlockDataMode(true);
 | 
						|
    readStreamHeader();
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the next deserialized object read from the underlying stream.
 | 
						|
   *
 | 
						|
   * This method can be overriden by a class by implementing
 | 
						|
   * <code>private void readObject (ObjectInputStream)</code>.
 | 
						|
   *
 | 
						|
   * If an exception is thrown from this method, the stream is left in
 | 
						|
   * an undefined state. This method can also throw Errors and
 | 
						|
   * RuntimeExceptions if caused by existing readResolve() user code.
 | 
						|
   *
 | 
						|
   * @return The object read from the underlying stream.
 | 
						|
   *
 | 
						|
   * @exception ClassNotFoundException The class that an object being
 | 
						|
   * read in belongs to cannot be found.
 | 
						|
   *
 | 
						|
   * @exception IOException Exception from underlying
 | 
						|
   * <code>InputStream</code>.
 | 
						|
   */
 | 
						|
  public final Object readObject()
 | 
						|
    throws ClassNotFoundException, IOException
 | 
						|
  {
 | 
						|
    return readObject(true);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * <p>
 | 
						|
   * Returns the next deserialized object read from the
 | 
						|
   * underlying stream in an unshared manner.  Any object
 | 
						|
   * returned by this method will not be returned by
 | 
						|
   * subsequent calls to either this method or {@link #readObject()}.
 | 
						|
   * </p>
 | 
						|
   * <p>
 | 
						|
   * This behaviour is achieved by:
 | 
						|
   * </p>
 | 
						|
   * <ul>
 | 
						|
   * <li>Marking the handles created by successful calls to this
 | 
						|
   * method, so that future calls to {@link #readObject()} or
 | 
						|
   * {@link #readUnshared()} will throw an {@link ObjectStreamException}
 | 
						|
   * rather than returning the same object reference.</li>
 | 
						|
   * <li>Throwing an {@link ObjectStreamException} if the next
 | 
						|
   * element in the stream is a reference to an earlier object.</li>
 | 
						|
   * </ul>
 | 
						|
   *
 | 
						|
   * @return a reference to the deserialized object.
 | 
						|
   * @throws ClassNotFoundException if the class of the object being
 | 
						|
   *                                deserialized can not be found.
 | 
						|
   * @throws StreamCorruptedException if information in the stream
 | 
						|
   *                                  is inconsistent.
 | 
						|
   * @throws ObjectStreamException if the next object has already been
 | 
						|
   *                               returned by an earlier call to this
 | 
						|
   *                               method or {@link #readObject()}.
 | 
						|
   * @throws OptionalDataException if primitive data occurs next in the stream.
 | 
						|
   * @throws IOException if an I/O error occurs from the stream.
 | 
						|
   * @since 1.4
 | 
						|
   * @see #readObject()
 | 
						|
   */
 | 
						|
  public Object readUnshared()
 | 
						|
    throws IOException, ClassNotFoundException
 | 
						|
  {
 | 
						|
    return readObject(false);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the next deserialized object read from the underlying stream.
 | 
						|
   *
 | 
						|
   * This method can be overriden by a class by implementing
 | 
						|
   * <code>private void readObject (ObjectInputStream)</code>.
 | 
						|
   *
 | 
						|
   * If an exception is thrown from this method, the stream is left in
 | 
						|
   * an undefined state. This method can also throw Errors and
 | 
						|
   * RuntimeExceptions if caused by existing readResolve() user code.
 | 
						|
   *
 | 
						|
   * @param shared true if handles created by this call should be shared
 | 
						|
   *               with later calls.
 | 
						|
   * @return The object read from the underlying stream.
 | 
						|
   *
 | 
						|
   * @exception ClassNotFoundException The class that an object being
 | 
						|
   * read in belongs to cannot be found.
 | 
						|
   *
 | 
						|
   * @exception IOException Exception from underlying
 | 
						|
   * <code>InputStream</code>.
 | 
						|
   */
 | 
						|
  private final Object readObject(boolean shared)
 | 
						|
    throws ClassNotFoundException, IOException
 | 
						|
  {
 | 
						|
    if (this.useSubclassMethod)
 | 
						|
      return readObjectOverride();
 | 
						|
 | 
						|
    Object ret_val;
 | 
						|
    boolean old_mode = setBlockDataMode(false);
 | 
						|
    byte marker = this.realInputStream.readByte();
 | 
						|
 | 
						|
    if (DEBUG)
 | 
						|
      depth += 2;
 | 
						|
 | 
						|
    if(dump) dumpElement("MARKER: 0x" + Integer.toHexString(marker) + " ");
 | 
						|
 | 
						|
    try
 | 
						|
      {
 | 
						|
        ret_val = parseContent(marker, shared);
 | 
						|
      }
 | 
						|
    finally
 | 
						|
      {
 | 
						|
        setBlockDataMode(old_mode);
 | 
						|
        if (DEBUG)
 | 
						|
          depth -= 2;
 | 
						|
      }
 | 
						|
 | 
						|
    return ret_val;
 | 
						|
  }
 | 
						|
 | 
						|
   /**
 | 
						|
    * Handles a content block within the stream, which begins with a marker
 | 
						|
    * byte indicating its type.
 | 
						|
    *
 | 
						|
    * @param marker the byte marker.
 | 
						|
    * @param shared true if handles created by this call should be shared
 | 
						|
    *               with later calls.
 | 
						|
    * @return an object which represents the parsed content.
 | 
						|
    * @throws ClassNotFoundException if the class of an object being
 | 
						|
    *                                read in cannot be found.
 | 
						|
    * @throws IOException if invalid data occurs or one is thrown by the
 | 
						|
    *                     underlying <code>InputStream</code>.
 | 
						|
    */
 | 
						|
   private Object parseContent(byte marker, boolean shared)
 | 
						|
     throws ClassNotFoundException, IOException
 | 
						|
   {
 | 
						|
     Object ret_val;
 | 
						|
     boolean is_consumed = false;
 | 
						|
 | 
						|
     switch (marker)
 | 
						|
       {
 | 
						|
       case TC_ENDBLOCKDATA:
 | 
						|
        {
 | 
						|
          ret_val = null;
 | 
						|
          is_consumed = true;
 | 
						|
          break;
 | 
						|
        }
 | 
						|
 | 
						|
       case TC_BLOCKDATA:
 | 
						|
       case TC_BLOCKDATALONG:
 | 
						|
        {
 | 
						|
          if (marker == TC_BLOCKDATALONG)
 | 
						|
            { if(dump) dumpElementln("BLOCKDATALONG"); }
 | 
						|
          else
 | 
						|
            { if(dump) dumpElementln("BLOCKDATA"); }
 | 
						|
          readNextBlock(marker);
 | 
						|
        }
 | 
						|
 | 
						|
       case TC_NULL:
 | 
						|
        {
 | 
						|
          if(dump) dumpElementln("NULL");
 | 
						|
          ret_val = null;
 | 
						|
          break;
 | 
						|
        }
 | 
						|
 | 
						|
       case TC_REFERENCE:
 | 
						|
        {
 | 
						|
          if(dump) dumpElement("REFERENCE ");
 | 
						|
          int oid = realInputStream.readInt();
 | 
						|
          if(dump) dumpElementln(Integer.toHexString(oid));
 | 
						|
          ret_val = lookupHandle(oid);
 | 
						|
          if (!shared)
 | 
						|
            throw new
 | 
						|
              InvalidObjectException("References can not be read unshared.");
 | 
						|
          break;
 | 
						|
        }
 | 
						|
 | 
						|
       case TC_CLASS:
 | 
						|
        {
 | 
						|
          if(dump) dumpElementln("CLASS");
 | 
						|
          ObjectStreamClass osc = (ObjectStreamClass)readObject();
 | 
						|
          Class clazz = osc.forClass();
 | 
						|
          assignNewHandle(clazz,shared);
 | 
						|
          ret_val = clazz;
 | 
						|
          break;
 | 
						|
        }
 | 
						|
 | 
						|
       case TC_PROXYCLASSDESC:
 | 
						|
        {
 | 
						|
          if(dump) dumpElementln("PROXYCLASS");
 | 
						|
 | 
						|
/* GCJ LOCAL */
 | 
						|
          // The grammar at this point is
 | 
						|
          //   TC_PROXYCLASSDESC newHandle proxyClassDescInfo
 | 
						|
          // i.e. we have to assign the handle immediately after
 | 
						|
          // reading the marker.
 | 
						|
          int handle = assignNewHandle("Dummy proxy",shared);
 | 
						|
/* END GCJ LOCAL */
 | 
						|
 | 
						|
          int n_intf = this.realInputStream.readInt();
 | 
						|
          String[] intfs = new String[n_intf];
 | 
						|
          for (int i = 0; i < n_intf; i++)
 | 
						|
            {
 | 
						|
              intfs[i] = this.realInputStream.readUTF();
 | 
						|
            }
 | 
						|
 | 
						|
          boolean oldmode = setBlockDataMode(true);
 | 
						|
          Class cl = resolveProxyClass(intfs);
 | 
						|
          setBlockDataMode(oldmode);
 | 
						|
 | 
						|
          ObjectStreamClass osc = lookupClass(cl);
 | 
						|
          if (osc.firstNonSerializableParentConstructor == null)
 | 
						|
            {
 | 
						|
              osc.realClassIsSerializable = true;
 | 
						|
              osc.fields = osc.fieldMapping = new ObjectStreamField[0];
 | 
						|
              try
 | 
						|
                {
 | 
						|
                  osc.firstNonSerializableParentConstructor =
 | 
						|
                    Object.class.getConstructor(new Class[0]);
 | 
						|
                }
 | 
						|
              catch (NoSuchMethodException x)
 | 
						|
                {
 | 
						|
                  throw (InternalError)
 | 
						|
                    new InternalError("Object ctor missing").initCause(x);
 | 
						|
                }
 | 
						|
            }
 | 
						|
/* GCJ LOCAL */
 | 
						|
          rememberHandle(osc,shared,handle);
 | 
						|
/* END GCJ LOCAL */
 | 
						|
 | 
						|
          if (!is_consumed)
 | 
						|
            {
 | 
						|
              byte b = this.realInputStream.readByte();
 | 
						|
              if (b != TC_ENDBLOCKDATA)
 | 
						|
                throw new IOException("Data annotated to class was not consumed." + b);
 | 
						|
            }
 | 
						|
          else
 | 
						|
            is_consumed = false;
 | 
						|
          ObjectStreamClass superosc = (ObjectStreamClass)readObject();
 | 
						|
          osc.setSuperclass(superosc);
 | 
						|
          ret_val = osc;
 | 
						|
          break;
 | 
						|
        }
 | 
						|
 | 
						|
       case TC_CLASSDESC:
 | 
						|
        {
 | 
						|
          ObjectStreamClass osc = readClassDescriptor();
 | 
						|
 | 
						|
          if (!is_consumed)
 | 
						|
            {
 | 
						|
              byte b = this.realInputStream.readByte();
 | 
						|
              if (b != TC_ENDBLOCKDATA)
 | 
						|
                throw new IOException("Data annotated to class was not consumed." + b);
 | 
						|
            }
 | 
						|
          else
 | 
						|
            is_consumed = false;
 | 
						|
 | 
						|
          osc.setSuperclass ((ObjectStreamClass)readObject());
 | 
						|
          ret_val = osc;
 | 
						|
          break;
 | 
						|
        }
 | 
						|
 | 
						|
       case TC_STRING:
 | 
						|
        {
 | 
						|
          if(dump) dumpElement("STRING=");
 | 
						|
          String s = this.realInputStream.readUTF();
 | 
						|
          if(dump) dumpElementln(s);
 | 
						|
          ret_val = processResolution(null, s, assignNewHandle(s,shared),
 | 
						|
                                      shared);
 | 
						|
          break;
 | 
						|
        }
 | 
						|
 | 
						|
       case TC_LONGSTRING:
 | 
						|
        {
 | 
						|
          if(dump) dumpElement("STRING=");
 | 
						|
          String s = this.realInputStream.readUTFLong();
 | 
						|
          if(dump) dumpElementln(s);
 | 
						|
          ret_val = processResolution(null, s, assignNewHandle(s,shared),
 | 
						|
                                      shared);
 | 
						|
          break;
 | 
						|
        }
 | 
						|
 | 
						|
       case TC_ARRAY:
 | 
						|
        {
 | 
						|
          if(dump) dumpElementln("ARRAY");
 | 
						|
          ObjectStreamClass osc = (ObjectStreamClass)readObject();
 | 
						|
          Class componentType = osc.forClass().getComponentType();
 | 
						|
          if(dump) dumpElement("ARRAY LENGTH=");
 | 
						|
          int length = this.realInputStream.readInt();
 | 
						|
          if(dump) dumpElementln (length + "; COMPONENT TYPE=" + componentType);
 | 
						|
          Object array = Array.newInstance(componentType, length);
 | 
						|
          int handle = assignNewHandle(array,shared);
 | 
						|
          readArrayElements(array, componentType);
 | 
						|
          if(dump)
 | 
						|
            for (int i = 0, len = Array.getLength(array); i < len; i++)
 | 
						|
              dumpElementln("  ELEMENT[" + i + "]=", Array.get(array, i));
 | 
						|
          ret_val = processResolution(null, array, handle, shared);
 | 
						|
          break;
 | 
						|
        }
 | 
						|
 | 
						|
       case TC_OBJECT:
 | 
						|
        {
 | 
						|
          if(dump) dumpElementln("OBJECT");
 | 
						|
          ObjectStreamClass osc = (ObjectStreamClass)readObject();
 | 
						|
          Class clazz = osc.forClass();
 | 
						|
 | 
						|
          if (!osc.realClassIsSerializable)
 | 
						|
            throw new NotSerializableException
 | 
						|
              (clazz + " is not Serializable, and thus cannot be deserialized.");
 | 
						|
 | 
						|
          if (osc.realClassIsExternalizable)
 | 
						|
            {
 | 
						|
              Externalizable obj = osc.newInstance();
 | 
						|
 | 
						|
              int handle = assignNewHandle(obj,shared);
 | 
						|
 | 
						|
              boolean read_from_blocks = ((osc.getFlags() & SC_BLOCK_DATA) != 0);
 | 
						|
 | 
						|
              boolean oldmode = this.readDataFromBlock;
 | 
						|
              if (read_from_blocks)
 | 
						|
                setBlockDataMode(true);
 | 
						|
 | 
						|
              obj.readExternal(this);
 | 
						|
 | 
						|
              if (read_from_blocks)
 | 
						|
                {
 | 
						|
                  setBlockDataMode(oldmode);
 | 
						|
                  if (!oldmode)
 | 
						|
                    if (this.realInputStream.readByte() != TC_ENDBLOCKDATA)
 | 
						|
                      throw new IOException("No end of block data seen for class with readExternal (ObjectInputStream) method.");
 | 
						|
                }
 | 
						|
 | 
						|
              ret_val = processResolution(osc, obj, handle,shared);
 | 
						|
              break;
 | 
						|
 | 
						|
            } // end if (osc.realClassIsExternalizable)
 | 
						|
 | 
						|
          Object obj = newObject(clazz, osc.firstNonSerializableParentConstructor);
 | 
						|
 | 
						|
          int handle = assignNewHandle(obj,shared);
 | 
						|
          Object prevObject = this.currentObject;
 | 
						|
          ObjectStreamClass prevObjectStreamClass = this.currentObjectStreamClass;
 | 
						|
          TreeSet<ValidatorAndPriority> prevObjectValidators =
 | 
						|
            this.currentObjectValidators;
 | 
						|
 | 
						|
          this.currentObject = obj;
 | 
						|
          this.currentObjectValidators = null;
 | 
						|
          ObjectStreamClass[] hierarchy = hierarchy(clazz);
 | 
						|
 | 
						|
          for (int i = 0; i < hierarchy.length; i++)
 | 
						|
          {
 | 
						|
              this.currentObjectStreamClass = hierarchy[i];
 | 
						|
              if(dump) dumpElementln("Reading fields of " + this.currentObjectStreamClass.getName ());
 | 
						|
 | 
						|
              // XXX: should initialize fields in classes in the hierarchy
 | 
						|
              // that aren't in the stream
 | 
						|
              // should skip over classes in the stream that aren't in the
 | 
						|
              // real classes hierarchy
 | 
						|
 | 
						|
              Method readObjectMethod = this.currentObjectStreamClass.readObjectMethod;
 | 
						|
              if (readObjectMethod != null)
 | 
						|
                {
 | 
						|
                  fieldsAlreadyRead = false;
 | 
						|
                  boolean oldmode = setBlockDataMode(true);
 | 
						|
                  callReadMethod(readObjectMethod, this.currentObjectStreamClass.forClass(), obj);
 | 
						|
                  setBlockDataMode(oldmode);
 | 
						|
                }
 | 
						|
              else
 | 
						|
                {
 | 
						|
                  readFields(obj, currentObjectStreamClass);
 | 
						|
                }
 | 
						|
 | 
						|
              if (this.currentObjectStreamClass.hasWriteMethod())
 | 
						|
                {
 | 
						|
                  if(dump) dumpElement("ENDBLOCKDATA? ");
 | 
						|
                  try
 | 
						|
                    {
 | 
						|
                      /* Read blocks until an end marker */
 | 
						|
                      byte writeMarker = this.realInputStream.readByte();
 | 
						|
                      while (writeMarker != TC_ENDBLOCKDATA)
 | 
						|
                        {
 | 
						|
                          parseContent(writeMarker, shared);
 | 
						|
                          writeMarker = this.realInputStream.readByte();
 | 
						|
                        }
 | 
						|
                      if(dump) dumpElementln("yes");
 | 
						|
                    }
 | 
						|
                  catch (EOFException e)
 | 
						|
                    {
 | 
						|
                      throw (IOException) new IOException
 | 
						|
                        ("No end of block data seen for class with readObject (ObjectInputStream) method.").initCause(e);
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
          this.currentObject = prevObject;
 | 
						|
          this.currentObjectStreamClass = prevObjectStreamClass;
 | 
						|
          ret_val = processResolution(osc, obj, handle, shared);
 | 
						|
          if (currentObjectValidators != null)
 | 
						|
            invokeValidators();
 | 
						|
          this.currentObjectValidators = prevObjectValidators;
 | 
						|
 | 
						|
          break;
 | 
						|
        }
 | 
						|
 | 
						|
       case TC_RESET:
 | 
						|
        if(dump) dumpElementln("RESET");
 | 
						|
        clearHandles();
 | 
						|
        ret_val = readObject();
 | 
						|
        break;
 | 
						|
 | 
						|
       case TC_EXCEPTION:
 | 
						|
        {
 | 
						|
          if(dump) dumpElement("EXCEPTION=");
 | 
						|
          Exception e = (Exception)readObject();
 | 
						|
          if(dump) dumpElementln(e.toString());
 | 
						|
          clearHandles();
 | 
						|
          throw new WriteAbortedException("Exception thrown during writing of stream", e);
 | 
						|
        }
 | 
						|
 | 
						|
       case TC_ENUM:
 | 
						|
         {
 | 
						|
           /* TC_ENUM classDesc newHandle enumConstantName */
 | 
						|
           if (dump)
 | 
						|
             dumpElementln("ENUM=");
 | 
						|
           ObjectStreamClass osc = (ObjectStreamClass) readObject();
 | 
						|
	   int enumHandle = assignNewHandle(null, shared);
 | 
						|
           String constantName = (String) readObject();
 | 
						|
           if (dump)
 | 
						|
             dumpElementln("CONSTANT NAME = " + constantName);
 | 
						|
           Class clazz = osc.forClass();
 | 
						|
           Enum instance = Enum.valueOf(clazz, constantName);
 | 
						|
	   rememberHandle(instance, shared, enumHandle);
 | 
						|
           ret_val = instance;
 | 
						|
           break;
 | 
						|
         }
 | 
						|
 | 
						|
       default:
 | 
						|
        throw new IOException("Unknown marker on stream: " + marker);
 | 
						|
      }
 | 
						|
    return ret_val;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * This method makes a partial check of types for the fields
 | 
						|
   * contained given in arguments. It checks primitive types of
 | 
						|
   * fields1 against non primitive types of fields2. This method
 | 
						|
   * assumes the two lists has already been sorted according to
 | 
						|
   * the Java specification.
 | 
						|
   *
 | 
						|
   * @param name Name of the class owning the given fields.
 | 
						|
   * @param fields1 First list to check.
 | 
						|
   * @param fields2 Second list to check.
 | 
						|
   * @throws InvalidClassException if a field in fields1, which has a primitive type, is a present
 | 
						|
   * in the non primitive part in fields2.
 | 
						|
   */
 | 
						|
  private void checkTypeConsistency(String name, ObjectStreamField[] fields1, ObjectStreamField[] fields2)
 | 
						|
    throws InvalidClassException
 | 
						|
  {
 | 
						|
    int nonPrimitive = 0;
 | 
						|
 | 
						|
    for (nonPrimitive = 0;
 | 
						|
         nonPrimitive < fields1.length
 | 
						|
           && fields1[nonPrimitive].isPrimitive(); nonPrimitive++)
 | 
						|
      {
 | 
						|
      }
 | 
						|
 | 
						|
    if (nonPrimitive == fields1.length)
 | 
						|
      return;
 | 
						|
 | 
						|
    int i = 0;
 | 
						|
    ObjectStreamField f1;
 | 
						|
    ObjectStreamField f2;
 | 
						|
 | 
						|
    while (i < fields2.length
 | 
						|
           && nonPrimitive < fields1.length)
 | 
						|
      {
 | 
						|
        f1 = fields1[nonPrimitive];
 | 
						|
        f2 = fields2[i];
 | 
						|
 | 
						|
        if (!f2.isPrimitive())
 | 
						|
          break;
 | 
						|
 | 
						|
        int compVal = f1.getName().compareTo (f2.getName());
 | 
						|
 | 
						|
        if (compVal < 0)
 | 
						|
          {
 | 
						|
            nonPrimitive++;
 | 
						|
          }
 | 
						|
        else if (compVal > 0)
 | 
						|
          {
 | 
						|
            i++;
 | 
						|
          }
 | 
						|
        else
 | 
						|
          {
 | 
						|
            throw new InvalidClassException
 | 
						|
              ("invalid field type for " + f2.getName() +
 | 
						|
               " in class " + name);
 | 
						|
          }
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * This method reads a class descriptor from the real input stream
 | 
						|
   * and use these data to create a new instance of ObjectStreamClass.
 | 
						|
   * Fields are sorted and ordered for the real read which occurs for
 | 
						|
   * each instance of the described class. Be aware that if you call that
 | 
						|
   * method you must ensure that the stream is synchronized, in the other
 | 
						|
   * case it may be completely desynchronized.
 | 
						|
   *
 | 
						|
   * @return A new instance of ObjectStreamClass containing the freshly
 | 
						|
   * created descriptor.
 | 
						|
   * @throws ClassNotFoundException if the required class to build the
 | 
						|
   * descriptor has not been found in the system.
 | 
						|
   * @throws IOException An input/output error occured.
 | 
						|
   * @throws InvalidClassException If there was a compatibility problem
 | 
						|
   * between the class present in the system and the serialized class.
 | 
						|
   */
 | 
						|
  protected ObjectStreamClass readClassDescriptor()
 | 
						|
    throws ClassNotFoundException, IOException
 | 
						|
  {
 | 
						|
    if(dump) dumpElement("CLASSDESC NAME=");
 | 
						|
    String name = this.realInputStream.readUTF();
 | 
						|
    if(dump) dumpElement(name + "; UID=");
 | 
						|
    long uid = this.realInputStream.readLong ();
 | 
						|
    if(dump) dumpElement(Long.toHexString(uid) + "; FLAGS=");
 | 
						|
    byte flags = this.realInputStream.readByte ();
 | 
						|
    if(dump) dumpElement(Integer.toHexString(flags) + "; FIELD COUNT=");
 | 
						|
    short field_count = this.realInputStream.readShort();
 | 
						|
    if(dump) dumpElementln(Short.toString(field_count));
 | 
						|
    ObjectStreamField[] fields = new ObjectStreamField[field_count];
 | 
						|
    ObjectStreamClass osc = new ObjectStreamClass(name, uid,
 | 
						|
                                                  flags, fields);
 | 
						|
    assignNewHandle(osc,true);
 | 
						|
 | 
						|
    for (int i = 0; i < field_count; i++)
 | 
						|
      {
 | 
						|
        if(dump) dumpElement("  TYPE CODE=");
 | 
						|
        char type_code = (char)this.realInputStream.readByte();
 | 
						|
        if(dump) dumpElement(type_code + "; FIELD NAME=");
 | 
						|
        String field_name = this.realInputStream.readUTF();
 | 
						|
        if(dump) dumpElementln(field_name);
 | 
						|
        String class_name;
 | 
						|
 | 
						|
        // If the type code is an array or an object we must
 | 
						|
        // decode a String here. In the other case we convert
 | 
						|
        // the type code and pass it to ObjectStreamField.
 | 
						|
        // Type codes are decoded by gnu.java.lang.reflect.TypeSignature.
 | 
						|
        if (type_code == 'L' || type_code == '[')
 | 
						|
          class_name = (String)readObject();
 | 
						|
        else
 | 
						|
          class_name = String.valueOf(type_code);
 | 
						|
 | 
						|
        fields[i] =
 | 
						|
          new ObjectStreamField(field_name, class_name);
 | 
						|
      }
 | 
						|
 | 
						|
    /* Now that fields have been read we may resolve the class
 | 
						|
     * (and read annotation if needed). */
 | 
						|
    Class clazz = resolveClass(osc);
 | 
						|
    ClassLoader loader = clazz.getClassLoader();
 | 
						|
    for (int i = 0; i < field_count; i++)
 | 
						|
      {
 | 
						|
        fields[i].resolveType(loader);
 | 
						|
      }
 | 
						|
    boolean oldmode = setBlockDataMode(true);
 | 
						|
    osc.setClass(clazz, lookupClass(clazz.getSuperclass()));
 | 
						|
    classLookupTable.put(clazz, osc);
 | 
						|
    setBlockDataMode(oldmode);
 | 
						|
 | 
						|
    // find the first non-serializable class in clazz's inheritance hierarchy
 | 
						|
    Class first_nonserial = clazz.getSuperclass();
 | 
						|
    // Maybe it is a primitive class, those don't have a super class,
 | 
						|
    // or Object itself.  Otherwise we can keep getting the superclass
 | 
						|
    // till we hit the Object class, or some other non-serializable class.
 | 
						|
 | 
						|
    if (first_nonserial == null)
 | 
						|
      first_nonserial = clazz;
 | 
						|
    else
 | 
						|
      while (Serializable.class.isAssignableFrom(first_nonserial))
 | 
						|
        first_nonserial = first_nonserial.getSuperclass();
 | 
						|
 | 
						|
    final Class local_constructor_class = first_nonserial;
 | 
						|
 | 
						|
    osc.firstNonSerializableParentConstructor =
 | 
						|
        (Constructor)AccessController.doPrivileged(new PrivilegedAction()
 | 
						|
          {
 | 
						|
            public Object run()
 | 
						|
            {
 | 
						|
              try
 | 
						|
                {
 | 
						|
                  Constructor c = local_constructor_class.
 | 
						|
                                    getDeclaredConstructor(new Class[0]);
 | 
						|
                  if (Modifier.isPrivate(c.getModifiers()))
 | 
						|
                    return null;
 | 
						|
                  return c;
 | 
						|
                }
 | 
						|
              catch (NoSuchMethodException e)
 | 
						|
                {
 | 
						|
                  // error will be reported later, in newObject()
 | 
						|
                  return null;
 | 
						|
                }
 | 
						|
            }
 | 
						|
          });
 | 
						|
 | 
						|
    osc.realClassIsSerializable = Serializable.class.isAssignableFrom(clazz);
 | 
						|
    osc.realClassIsExternalizable = Externalizable.class.isAssignableFrom(clazz);
 | 
						|
 | 
						|
    ObjectStreamField[] stream_fields = osc.fields;
 | 
						|
    ObjectStreamField[] real_fields = ObjectStreamClass.lookupForClassObject(clazz).fields;
 | 
						|
    ObjectStreamField[] fieldmapping = new ObjectStreamField[2 * Math.max(stream_fields.length, real_fields.length)];
 | 
						|
 | 
						|
    int stream_idx = 0;
 | 
						|
    int real_idx = 0;
 | 
						|
    int map_idx = 0;
 | 
						|
 | 
						|
    /*
 | 
						|
     * Check that there is no type inconsistencies between the lists.
 | 
						|
     * A special checking must be done for the two groups: primitive types and
 | 
						|
     * not primitive types.
 | 
						|
     */
 | 
						|
    checkTypeConsistency(name, real_fields, stream_fields);
 | 
						|
    checkTypeConsistency(name, stream_fields, real_fields);
 | 
						|
 | 
						|
 | 
						|
    while (stream_idx < stream_fields.length
 | 
						|
           || real_idx < real_fields.length)
 | 
						|
      {
 | 
						|
        ObjectStreamField stream_field = null;
 | 
						|
        ObjectStreamField real_field = null;
 | 
						|
 | 
						|
        if (stream_idx == stream_fields.length)
 | 
						|
          {
 | 
						|
            real_field = real_fields[real_idx++];
 | 
						|
          }
 | 
						|
        else if (real_idx == real_fields.length)
 | 
						|
          {
 | 
						|
            stream_field = stream_fields[stream_idx++];
 | 
						|
          }
 | 
						|
        else
 | 
						|
          {
 | 
						|
            int comp_val =
 | 
						|
              real_fields[real_idx].compareTo (stream_fields[stream_idx]);
 | 
						|
 | 
						|
            if (comp_val < 0)
 | 
						|
              {
 | 
						|
                real_field = real_fields[real_idx++];
 | 
						|
              }
 | 
						|
            else if (comp_val > 0)
 | 
						|
              {
 | 
						|
                stream_field = stream_fields[stream_idx++];
 | 
						|
              }
 | 
						|
            else
 | 
						|
              {
 | 
						|
                stream_field = stream_fields[stream_idx++];
 | 
						|
                real_field = real_fields[real_idx++];
 | 
						|
                if (stream_field.getType() != real_field.getType())
 | 
						|
                  throw new InvalidClassException
 | 
						|
                    ("invalid field type for " + real_field.getName() +
 | 
						|
                     " in class " + name);
 | 
						|
              }
 | 
						|
          }
 | 
						|
 | 
						|
        /* If some of stream_fields does not correspond to any of real_fields,
 | 
						|
         * or the opposite, then fieldmapping will go short.
 | 
						|
         */
 | 
						|
        if (map_idx == fieldmapping.length)
 | 
						|
          {
 | 
						|
            ObjectStreamField[] newfieldmapping =
 | 
						|
              new ObjectStreamField[fieldmapping.length + 2];
 | 
						|
            System.arraycopy(fieldmapping, 0,
 | 
						|
                             newfieldmapping, 0, fieldmapping.length);
 | 
						|
            fieldmapping = newfieldmapping;
 | 
						|
          }
 | 
						|
        fieldmapping[map_idx++] = stream_field;
 | 
						|
        fieldmapping[map_idx++] = real_field;
 | 
						|
      }
 | 
						|
    osc.fieldMapping = fieldmapping;
 | 
						|
 | 
						|
    return osc;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Reads the current objects non-transient, non-static fields from
 | 
						|
   * the current class from the underlying output stream.
 | 
						|
   *
 | 
						|
   * This method is intended to be called from within a object's
 | 
						|
   * <code>private void readObject (ObjectInputStream)</code>
 | 
						|
   * method.
 | 
						|
   *
 | 
						|
   * @exception ClassNotFoundException The class that an object being
 | 
						|
   * read in belongs to cannot be found.
 | 
						|
   *
 | 
						|
   * @exception NotActiveException This method was called from a
 | 
						|
   * context other than from the current object's and current class's
 | 
						|
   * <code>private void readObject (ObjectInputStream)</code>
 | 
						|
   * method.
 | 
						|
   *
 | 
						|
   * @exception IOException Exception from underlying
 | 
						|
   * <code>OutputStream</code>.
 | 
						|
   */
 | 
						|
  public void defaultReadObject()
 | 
						|
    throws ClassNotFoundException, IOException, NotActiveException
 | 
						|
  {
 | 
						|
    if (this.currentObject == null || this.currentObjectStreamClass == null)
 | 
						|
      throw new NotActiveException("defaultReadObject called by non-active"
 | 
						|
                                   + " class and/or object");
 | 
						|
 | 
						|
    if (fieldsAlreadyRead)
 | 
						|
      throw new NotActiveException("defaultReadObject called but fields "
 | 
						|
                                   + "already read from stream (by "
 | 
						|
                                   + "defaultReadObject or readFields)");
 | 
						|
 | 
						|
    boolean oldmode = setBlockDataMode(false);
 | 
						|
    readFields(this.currentObject, this.currentObjectStreamClass);
 | 
						|
    setBlockDataMode(oldmode);
 | 
						|
 | 
						|
    fieldsAlreadyRead = true;
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  /**
 | 
						|
   * Registers a <code>ObjectInputValidation</code> to be carried out
 | 
						|
   * on the object graph currently being deserialized before it is
 | 
						|
   * returned to the original caller of <code>readObject ()</code>.
 | 
						|
   * The order of validation for multiple
 | 
						|
   * <code>ObjectInputValidation</code>s can be controled using
 | 
						|
   * <code>priority</code>.  Validators with higher priorities are
 | 
						|
   * called first.
 | 
						|
   *
 | 
						|
   * @see java.io.ObjectInputValidation
 | 
						|
   *
 | 
						|
   * @exception InvalidObjectException <code>validator</code> is
 | 
						|
   * <code>null</code>
 | 
						|
   *
 | 
						|
   * @exception NotActiveException an attempt was made to add a
 | 
						|
   * validator outside of the <code>readObject</code> method of the
 | 
						|
   * object currently being deserialized
 | 
						|
   */
 | 
						|
  public void registerValidation(ObjectInputValidation validator,
 | 
						|
                                 int priority)
 | 
						|
    throws InvalidObjectException, NotActiveException
 | 
						|
  {
 | 
						|
    if (this.currentObject == null || this.currentObjectStreamClass == null)
 | 
						|
      throw new NotActiveException("registerValidation called by non-active "
 | 
						|
                                   + "class and/or object");
 | 
						|
 | 
						|
    if (validator == null)
 | 
						|
      throw new InvalidObjectException("attempt to add a null "
 | 
						|
                                       + "ObjectInputValidation object");
 | 
						|
 | 
						|
    if (currentObjectValidators == null)
 | 
						|
      currentObjectValidators = new TreeSet<ValidatorAndPriority>();
 | 
						|
 | 
						|
    currentObjectValidators.add(new ValidatorAndPriority(validator, priority));
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  /**
 | 
						|
   * Called when a class is being deserialized.  This is a hook to
 | 
						|
   * allow subclasses to read in information written by the
 | 
						|
   * <code>annotateClass (Class)</code> method of an
 | 
						|
   * <code>ObjectOutputStream</code>.
 | 
						|
   *
 | 
						|
   * This implementation looks up the active call stack for a
 | 
						|
   * <code>ClassLoader</code>; if a <code>ClassLoader</code> is found,
 | 
						|
   * it is used to load the class associated with <code>osc</code>,
 | 
						|
   * otherwise, the default system <code>ClassLoader</code> is used.
 | 
						|
   *
 | 
						|
   * @exception IOException Exception from underlying
 | 
						|
   * <code>OutputStream</code>.
 | 
						|
   *
 | 
						|
   * @see java.io.ObjectOutputStream#annotateClass (java.lang.Class)
 | 
						|
   */
 | 
						|
  protected Class<?> resolveClass(ObjectStreamClass osc)
 | 
						|
    throws ClassNotFoundException, IOException
 | 
						|
  {
 | 
						|
    String name = osc.getName();
 | 
						|
    try
 | 
						|
      {
 | 
						|
        return Class.forName(name, true, currentLoader());
 | 
						|
      }
 | 
						|
    catch(ClassNotFoundException x)
 | 
						|
      {
 | 
						|
        if (name.equals("void"))
 | 
						|
          return Void.TYPE;
 | 
						|
        else if (name.equals("boolean"))
 | 
						|
          return Boolean.TYPE;
 | 
						|
        else if (name.equals("byte"))
 | 
						|
          return Byte.TYPE;
 | 
						|
        else if (name.equals("char"))
 | 
						|
          return Character.TYPE;
 | 
						|
        else if (name.equals("short"))
 | 
						|
          return Short.TYPE;
 | 
						|
        else if (name.equals("int"))
 | 
						|
          return Integer.TYPE;
 | 
						|
        else if (name.equals("long"))
 | 
						|
          return Long.TYPE;
 | 
						|
        else if (name.equals("float"))
 | 
						|
          return Float.TYPE;
 | 
						|
        else if (name.equals("double"))
 | 
						|
          return Double.TYPE;
 | 
						|
        else
 | 
						|
          throw x;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the most recent user defined ClassLoader on the execution stack
 | 
						|
   * or null if none is found.
 | 
						|
   */
 | 
						|
  private ClassLoader currentLoader()
 | 
						|
  {
 | 
						|
    return VMStackWalker.firstNonNullClassLoader();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Lookup a class stored in the local hashtable. If it is not
 | 
						|
   * use the global lookup function in ObjectStreamClass to build
 | 
						|
   * the ObjectStreamClass. This method is requested according to
 | 
						|
   * the behaviour detected in the JDK by Kaffe's team.
 | 
						|
   *
 | 
						|
   * @param clazz Class to lookup in the hash table or for which
 | 
						|
   * we must build a descriptor.
 | 
						|
   * @return A valid instance of ObjectStreamClass corresponding
 | 
						|
   * to the specified class.
 | 
						|
   */
 | 
						|
  private ObjectStreamClass lookupClass(Class clazz)
 | 
						|
  {
 | 
						|
    if (clazz == null)
 | 
						|
      return null;
 | 
						|
 | 
						|
    ObjectStreamClass oclazz;
 | 
						|
    oclazz = classLookupTable.get(clazz);
 | 
						|
    if (oclazz == null)
 | 
						|
      return ObjectStreamClass.lookup(clazz);
 | 
						|
    else
 | 
						|
      return oclazz;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Reconstruct class hierarchy the same way {@link
 | 
						|
   * java.io.ObjectStreamClass#hierarchy} does but using lookupClass
 | 
						|
   * instead of ObjectStreamClass.lookup.
 | 
						|
   *
 | 
						|
   * @param clazz This is the class for which we want the hierarchy.
 | 
						|
   *
 | 
						|
   * @return An array of valid {@link java.io.ObjectStreamClass} instances which
 | 
						|
   * represent the class hierarchy for clazz.
 | 
						|
   */
 | 
						|
  private ObjectStreamClass[] hierarchy(Class clazz)
 | 
						|
  {
 | 
						|
    ObjectStreamClass osc = lookupClass(clazz);
 | 
						|
 | 
						|
    return osc == null ? new ObjectStreamClass[0] : osc.hierarchy();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Allows subclasses to resolve objects that are read from the
 | 
						|
   * stream with other objects to be returned in their place.  This
 | 
						|
   * method is called the first time each object is encountered.
 | 
						|
   *
 | 
						|
   * This method must be enabled before it will be called in the
 | 
						|
   * serialization process.
 | 
						|
   *
 | 
						|
   * @exception IOException Exception from underlying
 | 
						|
   * <code>OutputStream</code>.
 | 
						|
   *
 | 
						|
   * @see #enableResolveObject(boolean)
 | 
						|
   */
 | 
						|
  protected Object resolveObject(Object obj) throws IOException
 | 
						|
  {
 | 
						|
    return obj;
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  protected Class<?> resolveProxyClass(String[] intfs)
 | 
						|
    throws IOException, ClassNotFoundException
 | 
						|
  {
 | 
						|
    ClassLoader cl = currentLoader();
 | 
						|
 | 
						|
    Class<?>[] clss = new Class<?>[intfs.length];
 | 
						|
    if(cl == null)
 | 
						|
      {
 | 
						|
        for (int i = 0; i < intfs.length; i++)
 | 
						|
          clss[i] = Class.forName(intfs[i]);
 | 
						|
        cl = ClassLoader.getSystemClassLoader();
 | 
						|
      }
 | 
						|
    else
 | 
						|
      for (int i = 0; i < intfs.length; i++)
 | 
						|
        clss[i] = Class.forName(intfs[i], false, cl);
 | 
						|
    try
 | 
						|
      {
 | 
						|
        return Proxy.getProxyClass(cl, clss);
 | 
						|
      }
 | 
						|
    catch (IllegalArgumentException e)
 | 
						|
      {
 | 
						|
        throw new ClassNotFoundException(null, e);
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * If <code>enable</code> is <code>true</code> and this object is
 | 
						|
   * trusted, then <code>resolveObject (Object)</code> will be called
 | 
						|
   * in subsequent calls to <code>readObject (Object)</code>.
 | 
						|
   * Otherwise, <code>resolveObject (Object)</code> will not be called.
 | 
						|
   *
 | 
						|
   * @exception SecurityException This class is not trusted.
 | 
						|
   */
 | 
						|
  protected boolean enableResolveObject (boolean enable)
 | 
						|
    throws SecurityException
 | 
						|
  {
 | 
						|
    if (enable)
 | 
						|
      {
 | 
						|
        SecurityManager sm = System.getSecurityManager();
 | 
						|
        if (sm != null)
 | 
						|
          sm.checkPermission(new SerializablePermission("enableSubstitution"));
 | 
						|
      }
 | 
						|
 | 
						|
    boolean old_val = this.resolveEnabled;
 | 
						|
    this.resolveEnabled = enable;
 | 
						|
    return old_val;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Reads stream magic and stream version information from the
 | 
						|
   * underlying stream.
 | 
						|
   *
 | 
						|
   * @exception IOException Exception from underlying stream.
 | 
						|
   *
 | 
						|
   * @exception StreamCorruptedException An invalid stream magic
 | 
						|
   * number or stream version was read from the stream.
 | 
						|
   */
 | 
						|
  protected void readStreamHeader()
 | 
						|
    throws IOException, StreamCorruptedException
 | 
						|
  {
 | 
						|
    if(dump) dumpElement("STREAM MAGIC ");
 | 
						|
    if (this.realInputStream.readShort() != STREAM_MAGIC)
 | 
						|
      throw new StreamCorruptedException("Invalid stream magic number");
 | 
						|
 | 
						|
    if(dump) dumpElementln("STREAM VERSION ");
 | 
						|
    if (this.realInputStream.readShort() != STREAM_VERSION)
 | 
						|
      throw new StreamCorruptedException("Invalid stream version number");
 | 
						|
  }
 | 
						|
 | 
						|
  public int read() throws IOException
 | 
						|
  {
 | 
						|
    if (this.readDataFromBlock)
 | 
						|
      {
 | 
						|
        if (this.blockDataPosition >= this.blockDataBytes)
 | 
						|
          readNextBlock();
 | 
						|
        return (this.blockData[this.blockDataPosition++] & 0xff);
 | 
						|
      }
 | 
						|
    else
 | 
						|
      return this.realInputStream.read();
 | 
						|
  }
 | 
						|
 | 
						|
  public int read(byte[] data, int offset, int length) throws IOException
 | 
						|
  {
 | 
						|
    if (this.readDataFromBlock)
 | 
						|
      {
 | 
						|
        int remain = this.blockDataBytes - this.blockDataPosition;
 | 
						|
        if (remain == 0)
 | 
						|
          {
 | 
						|
            readNextBlock();
 | 
						|
            remain = this.blockDataBytes - this.blockDataPosition;
 | 
						|
          }
 | 
						|
        length = Math.min(length, remain);
 | 
						|
        System.arraycopy(this.blockData, this.blockDataPosition,
 | 
						|
                         data, offset, length);
 | 
						|
        this.blockDataPosition += length;
 | 
						|
 | 
						|
        return length;
 | 
						|
      }
 | 
						|
    else
 | 
						|
      return this.realInputStream.read(data, offset, length);
 | 
						|
  }
 | 
						|
 | 
						|
  public int available() throws IOException
 | 
						|
  {
 | 
						|
    if (this.readDataFromBlock)
 | 
						|
      {
 | 
						|
        if (this.blockDataPosition >= this.blockDataBytes)
 | 
						|
          readNextBlock ();
 | 
						|
 | 
						|
        return this.blockDataBytes - this.blockDataPosition;
 | 
						|
      }
 | 
						|
    else
 | 
						|
      return this.realInputStream.available();
 | 
						|
  }
 | 
						|
 | 
						|
  public void close() throws IOException
 | 
						|
  {
 | 
						|
    this.realInputStream.close();
 | 
						|
  }
 | 
						|
 | 
						|
  public boolean readBoolean() throws IOException
 | 
						|
  {
 | 
						|
    boolean switchmode = true;
 | 
						|
    boolean oldmode = this.readDataFromBlock;
 | 
						|
    if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
 | 
						|
      switchmode = false;
 | 
						|
    if (switchmode)
 | 
						|
      oldmode = setBlockDataMode (true);
 | 
						|
    boolean value = this.dataInputStream.readBoolean ();
 | 
						|
    if (switchmode)
 | 
						|
      setBlockDataMode (oldmode);
 | 
						|
    return value;
 | 
						|
  }
 | 
						|
 | 
						|
  public byte readByte() throws IOException
 | 
						|
  {
 | 
						|
    boolean switchmode = true;
 | 
						|
    boolean oldmode = this.readDataFromBlock;
 | 
						|
    if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
 | 
						|
      switchmode = false;
 | 
						|
    if (switchmode)
 | 
						|
      oldmode = setBlockDataMode(true);
 | 
						|
    byte value = this.dataInputStream.readByte();
 | 
						|
    if (switchmode)
 | 
						|
      setBlockDataMode(oldmode);
 | 
						|
    return value;
 | 
						|
  }
 | 
						|
 | 
						|
  public int readUnsignedByte() throws IOException
 | 
						|
  {
 | 
						|
    boolean switchmode = true;
 | 
						|
    boolean oldmode = this.readDataFromBlock;
 | 
						|
    if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
 | 
						|
      switchmode = false;
 | 
						|
    if (switchmode)
 | 
						|
      oldmode = setBlockDataMode(true);
 | 
						|
    int value = this.dataInputStream.readUnsignedByte();
 | 
						|
    if (switchmode)
 | 
						|
      setBlockDataMode(oldmode);
 | 
						|
    return value;
 | 
						|
  }
 | 
						|
 | 
						|
  public short readShort() throws IOException
 | 
						|
  {
 | 
						|
    boolean switchmode = true;
 | 
						|
    boolean oldmode = this.readDataFromBlock;
 | 
						|
    if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
 | 
						|
      switchmode = false;
 | 
						|
    if (switchmode)
 | 
						|
      oldmode = setBlockDataMode(true);
 | 
						|
    short value = this.dataInputStream.readShort();
 | 
						|
    if (switchmode)
 | 
						|
      setBlockDataMode(oldmode);
 | 
						|
    return value;
 | 
						|
  }
 | 
						|
 | 
						|
  public int readUnsignedShort() throws IOException
 | 
						|
  {
 | 
						|
    boolean switchmode = true;
 | 
						|
    boolean oldmode = this.readDataFromBlock;
 | 
						|
    if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
 | 
						|
      switchmode = false;
 | 
						|
    if (switchmode)
 | 
						|
      oldmode = setBlockDataMode(true);
 | 
						|
    int value = this.dataInputStream.readUnsignedShort();
 | 
						|
    if (switchmode)
 | 
						|
      setBlockDataMode(oldmode);
 | 
						|
    return value;
 | 
						|
  }
 | 
						|
 | 
						|
  public char readChar() throws IOException
 | 
						|
  {
 | 
						|
    boolean switchmode = true;
 | 
						|
    boolean oldmode = this.readDataFromBlock;
 | 
						|
    if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
 | 
						|
      switchmode = false;
 | 
						|
    if (switchmode)
 | 
						|
      oldmode = setBlockDataMode(true);
 | 
						|
    char value = this.dataInputStream.readChar();
 | 
						|
    if (switchmode)
 | 
						|
      setBlockDataMode(oldmode);
 | 
						|
    return value;
 | 
						|
  }
 | 
						|
 | 
						|
  public int readInt() throws IOException
 | 
						|
  {
 | 
						|
    boolean switchmode = true;
 | 
						|
    boolean oldmode = this.readDataFromBlock;
 | 
						|
    if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 4)
 | 
						|
      switchmode = false;
 | 
						|
    if (switchmode)
 | 
						|
      oldmode = setBlockDataMode(true);
 | 
						|
    int value = this.dataInputStream.readInt();
 | 
						|
    if (switchmode)
 | 
						|
      setBlockDataMode(oldmode);
 | 
						|
    return value;
 | 
						|
  }
 | 
						|
 | 
						|
  public long readLong() throws IOException
 | 
						|
  {
 | 
						|
    boolean switchmode = true;
 | 
						|
    boolean oldmode = this.readDataFromBlock;
 | 
						|
    if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 8)
 | 
						|
      switchmode = false;
 | 
						|
    if (switchmode)
 | 
						|
      oldmode = setBlockDataMode(true);
 | 
						|
    long value = this.dataInputStream.readLong();
 | 
						|
    if (switchmode)
 | 
						|
      setBlockDataMode(oldmode);
 | 
						|
    return value;
 | 
						|
  }
 | 
						|
 | 
						|
  public float readFloat() throws IOException
 | 
						|
  {
 | 
						|
    boolean switchmode = true;
 | 
						|
    boolean oldmode = this.readDataFromBlock;
 | 
						|
    if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 4)
 | 
						|
      switchmode = false;
 | 
						|
    if (switchmode)
 | 
						|
      oldmode = setBlockDataMode(true);
 | 
						|
    float value = this.dataInputStream.readFloat();
 | 
						|
    if (switchmode)
 | 
						|
      setBlockDataMode(oldmode);
 | 
						|
    return value;
 | 
						|
  }
 | 
						|
 | 
						|
  public double readDouble() throws IOException
 | 
						|
  {
 | 
						|
    boolean switchmode = true;
 | 
						|
    boolean oldmode = this.readDataFromBlock;
 | 
						|
    if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 8)
 | 
						|
      switchmode = false;
 | 
						|
    if (switchmode)
 | 
						|
      oldmode = setBlockDataMode(true);
 | 
						|
    double value = this.dataInputStream.readDouble();
 | 
						|
    if (switchmode)
 | 
						|
      setBlockDataMode(oldmode);
 | 
						|
    return value;
 | 
						|
  }
 | 
						|
 | 
						|
  public void readFully(byte data[]) throws IOException
 | 
						|
  {
 | 
						|
    this.dataInputStream.readFully(data);
 | 
						|
  }
 | 
						|
 | 
						|
  public void readFully(byte data[], int offset, int size)
 | 
						|
    throws IOException
 | 
						|
  {
 | 
						|
    this.dataInputStream.readFully(data, offset, size);
 | 
						|
  }
 | 
						|
 | 
						|
  public int skipBytes(int len) throws IOException
 | 
						|
  {
 | 
						|
    return this.dataInputStream.skipBytes(len);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * @deprecated
 | 
						|
   * @see java.io.DataInputStream#readLine ()
 | 
						|
   */
 | 
						|
  public String readLine() throws IOException
 | 
						|
  {
 | 
						|
    return this.dataInputStream.readLine();
 | 
						|
  }
 | 
						|
 | 
						|
  public String readUTF() throws IOException
 | 
						|
  {
 | 
						|
    return this.dataInputStream.readUTF();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * This class allows a class to specify exactly which fields should
 | 
						|
   * be read, and what values should be read for these fields.
 | 
						|
   *
 | 
						|
   * XXX: finish up comments
 | 
						|
   */
 | 
						|
  public abstract static class GetField
 | 
						|
  {
 | 
						|
    public abstract ObjectStreamClass getObjectStreamClass();
 | 
						|
 | 
						|
    public abstract boolean defaulted(String name)
 | 
						|
      throws IOException, IllegalArgumentException;
 | 
						|
 | 
						|
    public abstract boolean get(String name, boolean defvalue)
 | 
						|
      throws IOException, IllegalArgumentException;
 | 
						|
 | 
						|
    public abstract char get(String name, char defvalue)
 | 
						|
      throws IOException, IllegalArgumentException;
 | 
						|
 | 
						|
    public abstract byte get(String name, byte defvalue)
 | 
						|
      throws IOException, IllegalArgumentException;
 | 
						|
 | 
						|
    public abstract short get(String name, short defvalue)
 | 
						|
      throws IOException, IllegalArgumentException;
 | 
						|
 | 
						|
    public abstract int get(String name, int defvalue)
 | 
						|
      throws IOException, IllegalArgumentException;
 | 
						|
 | 
						|
    public abstract long get(String name, long defvalue)
 | 
						|
      throws IOException, IllegalArgumentException;
 | 
						|
 | 
						|
    public abstract float get(String name, float defvalue)
 | 
						|
      throws IOException, IllegalArgumentException;
 | 
						|
 | 
						|
    public abstract double get(String name, double defvalue)
 | 
						|
      throws IOException, IllegalArgumentException;
 | 
						|
 | 
						|
    public abstract Object get(String name, Object defvalue)
 | 
						|
      throws IOException, IllegalArgumentException;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * This method should be called by a method called 'readObject' in the
 | 
						|
   * deserializing class (if present). It cannot (and should not)be called
 | 
						|
   * outside of it. Its goal is to read all fields in the real input stream
 | 
						|
   * and keep them accessible through the {@link GetField} class. Calling
 | 
						|
   * this method will not alter the deserializing object.
 | 
						|
   *
 | 
						|
   * @return A valid freshly created 'GetField' instance to get access to
 | 
						|
   * the deserialized stream.
 | 
						|
   * @throws IOException An input/output exception occured.
 | 
						|
   * @throws ClassNotFoundException
 | 
						|
   * @throws NotActiveException
 | 
						|
   */
 | 
						|
  public GetField readFields()
 | 
						|
    throws IOException, ClassNotFoundException, NotActiveException
 | 
						|
  {
 | 
						|
    if (this.currentObject == null || this.currentObjectStreamClass == null)
 | 
						|
      throw new NotActiveException("readFields called by non-active class and/or object");
 | 
						|
 | 
						|
    if (prereadFields != null)
 | 
						|
      return prereadFields;
 | 
						|
 | 
						|
    if (fieldsAlreadyRead)
 | 
						|
      throw new NotActiveException("readFields called but fields already read from"
 | 
						|
                                   + " stream (by defaultReadObject or readFields)");
 | 
						|
 | 
						|
    final ObjectStreamClass clazz = this.currentObjectStreamClass;
 | 
						|
    final byte[] prim_field_data = new byte[clazz.primFieldSize];
 | 
						|
    final Object[] objs = new Object[clazz.objectFieldCount];
 | 
						|
 | 
						|
    // Apparently Block data is not used with GetField as per
 | 
						|
    // empirical evidence against JDK 1.2.  Also see Mauve test
 | 
						|
    // java.io.ObjectInputOutput.Test.GetPutField.
 | 
						|
    boolean oldmode = setBlockDataMode(false);
 | 
						|
    readFully(prim_field_data);
 | 
						|
    for (int i = 0; i < objs.length; ++ i)
 | 
						|
      objs[i] = readObject();
 | 
						|
    setBlockDataMode(oldmode);
 | 
						|
 | 
						|
    prereadFields = new GetField()
 | 
						|
      {
 | 
						|
        public ObjectStreamClass getObjectStreamClass()
 | 
						|
        {
 | 
						|
          return clazz;
 | 
						|
        }
 | 
						|
 | 
						|
        public boolean defaulted(String name)
 | 
						|
          throws IOException, IllegalArgumentException
 | 
						|
        {
 | 
						|
          ObjectStreamField f = clazz.getField(name);
 | 
						|
 | 
						|
          /* First if we have a serialized field use the descriptor */
 | 
						|
          if (f != null)
 | 
						|
            {
 | 
						|
              /* It is in serialPersistentFields but setClass tells us
 | 
						|
               * it should not be set. This value is defaulted.
 | 
						|
               */
 | 
						|
              if (f.isPersistent() && !f.isToSet())
 | 
						|
                return true;
 | 
						|
 | 
						|
              return false;
 | 
						|
            }
 | 
						|
 | 
						|
          /* This is not a serialized field. There should be
 | 
						|
           * a default value only if the field really exists.
 | 
						|
           */
 | 
						|
          try
 | 
						|
            {
 | 
						|
              return (clazz.forClass().getDeclaredField (name) != null);
 | 
						|
            }
 | 
						|
          catch (NoSuchFieldException e)
 | 
						|
            {
 | 
						|
              throw new IllegalArgumentException(e);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        public boolean get(String name, boolean defvalue)
 | 
						|
          throws IOException, IllegalArgumentException
 | 
						|
        {
 | 
						|
          ObjectStreamField field = getField(name, Boolean.TYPE);
 | 
						|
 | 
						|
          if (field == null)
 | 
						|
            return defvalue;
 | 
						|
 | 
						|
          return prim_field_data[field.getOffset()] == 0 ? false : true;
 | 
						|
        }
 | 
						|
 | 
						|
        public char get(String name, char defvalue)
 | 
						|
          throws IOException, IllegalArgumentException
 | 
						|
        {
 | 
						|
          ObjectStreamField field = getField(name, Character.TYPE);
 | 
						|
 | 
						|
          if (field == null)
 | 
						|
            return defvalue;
 | 
						|
 | 
						|
          int off = field.getOffset();
 | 
						|
 | 
						|
          return (char)(((prim_field_data[off++] & 0xFF) << 8)
 | 
						|
                        | (prim_field_data[off] & 0xFF));
 | 
						|
        }
 | 
						|
 | 
						|
        public byte get(String name, byte defvalue)
 | 
						|
          throws IOException, IllegalArgumentException
 | 
						|
        {
 | 
						|
          ObjectStreamField field = getField(name, Byte.TYPE);
 | 
						|
 | 
						|
          if (field == null)
 | 
						|
            return defvalue;
 | 
						|
 | 
						|
          return prim_field_data[field.getOffset()];
 | 
						|
        }
 | 
						|
 | 
						|
        public short get(String name, short defvalue)
 | 
						|
          throws IOException, IllegalArgumentException
 | 
						|
        {
 | 
						|
          ObjectStreamField field = getField(name, Short.TYPE);
 | 
						|
 | 
						|
          if (field == null)
 | 
						|
            return defvalue;
 | 
						|
 | 
						|
          int off = field.getOffset();
 | 
						|
 | 
						|
          return (short)(((prim_field_data[off++] & 0xFF) << 8)
 | 
						|
                         | (prim_field_data[off] & 0xFF));
 | 
						|
        }
 | 
						|
 | 
						|
        public int get(String name, int defvalue)
 | 
						|
          throws IOException, IllegalArgumentException
 | 
						|
        {
 | 
						|
          ObjectStreamField field = getField(name, Integer.TYPE);
 | 
						|
 | 
						|
          if (field == null)
 | 
						|
            return defvalue;
 | 
						|
 | 
						|
          int off = field.getOffset();
 | 
						|
 | 
						|
          return ((prim_field_data[off++] & 0xFF) << 24)
 | 
						|
            | ((prim_field_data[off++] & 0xFF) << 16)
 | 
						|
            | ((prim_field_data[off++] & 0xFF) << 8)
 | 
						|
            | (prim_field_data[off] & 0xFF);
 | 
						|
        }
 | 
						|
 | 
						|
        public long get(String name, long defvalue)
 | 
						|
          throws IOException, IllegalArgumentException
 | 
						|
        {
 | 
						|
          ObjectStreamField field = getField(name, Long.TYPE);
 | 
						|
 | 
						|
          if (field == null)
 | 
						|
            return defvalue;
 | 
						|
 | 
						|
          int off = field.getOffset();
 | 
						|
 | 
						|
          return (long)(((prim_field_data[off++] & 0xFFL) << 56)
 | 
						|
                        | ((prim_field_data[off++] & 0xFFL) << 48)
 | 
						|
                        | ((prim_field_data[off++] & 0xFFL) << 40)
 | 
						|
                        | ((prim_field_data[off++] & 0xFFL) << 32)
 | 
						|
                        | ((prim_field_data[off++] & 0xFF) << 24)
 | 
						|
                        | ((prim_field_data[off++] & 0xFF) << 16)
 | 
						|
                        | ((prim_field_data[off++] & 0xFF) << 8)
 | 
						|
                        | (prim_field_data[off] & 0xFF));
 | 
						|
        }
 | 
						|
 | 
						|
        public float get(String name, float defvalue)
 | 
						|
          throws IOException, IllegalArgumentException
 | 
						|
        {
 | 
						|
          ObjectStreamField field = getField(name, Float.TYPE);
 | 
						|
 | 
						|
          if (field == null)
 | 
						|
            return defvalue;
 | 
						|
 | 
						|
          int off = field.getOffset();
 | 
						|
 | 
						|
          return Float.intBitsToFloat(((prim_field_data[off++] & 0xFF) << 24)
 | 
						|
                                      | ((prim_field_data[off++] & 0xFF) << 16)
 | 
						|
                                      | ((prim_field_data[off++] & 0xFF) << 8)
 | 
						|
                                      | (prim_field_data[off] & 0xFF));
 | 
						|
        }
 | 
						|
 | 
						|
        public double get(String name, double defvalue)
 | 
						|
          throws IOException, IllegalArgumentException
 | 
						|
        {
 | 
						|
          ObjectStreamField field = getField(name, Double.TYPE);
 | 
						|
 | 
						|
          if (field == null)
 | 
						|
            return defvalue;
 | 
						|
 | 
						|
          int off = field.getOffset();
 | 
						|
 | 
						|
          return Double.longBitsToDouble
 | 
						|
            ( (long) (((prim_field_data[off++] & 0xFFL) << 56)
 | 
						|
                      | ((prim_field_data[off++] & 0xFFL) << 48)
 | 
						|
                      | ((prim_field_data[off++] & 0xFFL) << 40)
 | 
						|
                      | ((prim_field_data[off++] & 0xFFL) << 32)
 | 
						|
                      | ((prim_field_data[off++] & 0xFF) << 24)
 | 
						|
                      | ((prim_field_data[off++] & 0xFF) << 16)
 | 
						|
                      | ((prim_field_data[off++] & 0xFF) << 8)
 | 
						|
                      | (prim_field_data[off] & 0xFF)));
 | 
						|
        }
 | 
						|
 | 
						|
        public Object get(String name, Object defvalue)
 | 
						|
          throws IOException, IllegalArgumentException
 | 
						|
        {
 | 
						|
          ObjectStreamField field =
 | 
						|
            getField(name, defvalue == null ? null : defvalue.getClass ());
 | 
						|
 | 
						|
          if (field == null)
 | 
						|
            return defvalue;
 | 
						|
 | 
						|
          return objs[field.getOffset()];
 | 
						|
        }
 | 
						|
 | 
						|
        private ObjectStreamField getField(String name, Class type)
 | 
						|
          throws IllegalArgumentException
 | 
						|
        {
 | 
						|
          ObjectStreamField field = clazz.getField(name);
 | 
						|
          boolean illegal = false;
 | 
						|
 | 
						|
          // XXX This code is horrible and needs to be rewritten!
 | 
						|
          try
 | 
						|
            {
 | 
						|
              try
 | 
						|
                {
 | 
						|
                  Class field_type = field.getType();
 | 
						|
 | 
						|
                  if (type == field_type ||
 | 
						|
                      (type == null && !field_type.isPrimitive()))
 | 
						|
                    {
 | 
						|
                      /* See defaulted */
 | 
						|
                      return field;
 | 
						|
                    }
 | 
						|
 | 
						|
                  illegal = true;
 | 
						|
                  throw new IllegalArgumentException
 | 
						|
                    ("Field requested is of type "
 | 
						|
                     + field_type.getName()
 | 
						|
                     + ", but requested type was "
 | 
						|
                     + (type == null ?  "Object" : type.getName()));
 | 
						|
                }
 | 
						|
              catch (NullPointerException _)
 | 
						|
                {
 | 
						|
                  /* Here we catch NullPointerException, because it may
 | 
						|
                     only come from the call 'field.getType()'. If field
 | 
						|
                     is null, we have to return null and classpath ethic
 | 
						|
                     say we must try to avoid 'if (xxx == null)'.
 | 
						|
                  */
 | 
						|
                }
 | 
						|
              catch (IllegalArgumentException e)
 | 
						|
                {
 | 
						|
                  throw e;
 | 
						|
                }
 | 
						|
 | 
						|
              return null;
 | 
						|
            }
 | 
						|
          finally
 | 
						|
            {
 | 
						|
              /* If this is an unassigned field we should return
 | 
						|
               * the default value.
 | 
						|
               */
 | 
						|
              if (!illegal && field != null && !field.isToSet() && field.isPersistent())
 | 
						|
                return null;
 | 
						|
 | 
						|
              /* We do not want to modify transient fields. They should
 | 
						|
               * be left to 0.
 | 
						|
               */
 | 
						|
              try
 | 
						|
                {
 | 
						|
                  Field f = clazz.forClass().getDeclaredField(name);
 | 
						|
                  if (Modifier.isTransient(f.getModifiers()))
 | 
						|
                    throw new IllegalArgumentException
 | 
						|
                      ("no such field (non transient) " + name);
 | 
						|
                  if (field == null && f.getType() != type)
 | 
						|
                    throw new IllegalArgumentException
 | 
						|
                      ("Invalid requested type for field " + name);
 | 
						|
                }
 | 
						|
              catch (NoSuchFieldException e)
 | 
						|
                {
 | 
						|
                  if (field == null)
 | 
						|
                    throw new IllegalArgumentException(e);
 | 
						|
                }
 | 
						|
 | 
						|
            }
 | 
						|
        }
 | 
						|
      };
 | 
						|
 | 
						|
    fieldsAlreadyRead = true;
 | 
						|
    return prereadFields;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Protected constructor that allows subclasses to override
 | 
						|
   * deserialization.  This constructor should be called by subclasses
 | 
						|
   * that wish to override <code>readObject (Object)</code>.  This
 | 
						|
   * method does a security check <i>NOTE: currently not
 | 
						|
   * implemented</i>, then sets a flag that informs
 | 
						|
   * <code>readObject (Object)</code> to call the subclasses
 | 
						|
   * <code>readObjectOverride (Object)</code> method.
 | 
						|
   *
 | 
						|
   * @see #readObjectOverride()
 | 
						|
   */
 | 
						|
  protected ObjectInputStream()
 | 
						|
    throws IOException, SecurityException
 | 
						|
  {
 | 
						|
    SecurityManager sec_man = System.getSecurityManager();
 | 
						|
    if (sec_man != null)
 | 
						|
      sec_man.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
 | 
						|
    this.useSubclassMethod = true;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * This method allows subclasses to override the default
 | 
						|
   * de serialization mechanism provided by
 | 
						|
   * <code>ObjectInputStream</code>.  To make this method be used for
 | 
						|
   * writing objects, subclasses must invoke the 0-argument
 | 
						|
   * constructor on this class from their constructor.
 | 
						|
   *
 | 
						|
   * @see #ObjectInputStream()
 | 
						|
   */
 | 
						|
  protected Object readObjectOverride()
 | 
						|
    throws ClassNotFoundException, IOException, OptionalDataException
 | 
						|
  {
 | 
						|
    throw new IOException("Subclass of ObjectInputStream must implement readObjectOverride");
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Assigns the next available handle to <code>obj</code>.
 | 
						|
   *
 | 
						|
   * @param obj The object for which we want a new handle.
 | 
						|
   * @param shared True if the handle should be shared
 | 
						|
   *               with later calls.
 | 
						|
   * @return A valid handle for the specified object.
 | 
						|
   */
 | 
						|
  private int assignNewHandle(Object obj, boolean shared)
 | 
						|
  {
 | 
						|
    int handle = this.nextOID;
 | 
						|
    this.nextOID = handle + 1;
 | 
						|
    rememberHandle(obj,shared,handle);
 | 
						|
    return handle;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Remember the object associated with the given handle.
 | 
						|
   *
 | 
						|
   * @param obj an object
 | 
						|
   * @param shared true if the reference should be shared
 | 
						|
   *               with later calls.
 | 
						|
   * @param handle a handle, must be >= baseWireHandle
 | 
						|
   *
 | 
						|
   * @see #lookupHandle
 | 
						|
   */
 | 
						|
  private void rememberHandle(Object obj, boolean shared,
 | 
						|
                              int handle)
 | 
						|
  {
 | 
						|
    handles.put(handle, new Pair<Boolean,Object>(shared, obj));
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Look up the object associated with a given handle.
 | 
						|
   *
 | 
						|
   * @param handle a handle, must be >= baseWireHandle
 | 
						|
   * @return the object remembered for handle or null if none.
 | 
						|
   * @throws StreamCorruptedException if the handle is invalid.
 | 
						|
   * @throws InvalidObjectException if the reference is not shared.
 | 
						|
   * @see #rememberHandle
 | 
						|
   */
 | 
						|
  private Object lookupHandle(int handle)
 | 
						|
    throws ObjectStreamException
 | 
						|
  {
 | 
						|
    Pair<Boolean,Object> result = handles.get(handle);
 | 
						|
    if (result == null)
 | 
						|
      throw new StreamCorruptedException("The handle, " +
 | 
						|
                                         Integer.toHexString(handle) +
 | 
						|
                                         ", is invalid.");
 | 
						|
    if (!result.getLeft())
 | 
						|
      throw new InvalidObjectException("The handle, " +
 | 
						|
                                       Integer.toHexString(handle) +
 | 
						|
                                       ", is not shared.");
 | 
						|
    return result.getRight();
 | 
						|
  }
 | 
						|
 | 
						|
  private Object processResolution(ObjectStreamClass osc, Object obj, int handle,
 | 
						|
                                   boolean shared)
 | 
						|
    throws IOException
 | 
						|
  {
 | 
						|
    if (osc != null && obj instanceof Serializable)
 | 
						|
      {
 | 
						|
        try
 | 
						|
          {
 | 
						|
            Method m = osc.readResolveMethod;
 | 
						|
            if(m != null)
 | 
						|
            {
 | 
						|
                obj = m.invoke(obj, new Object[] {});
 | 
						|
            }
 | 
						|
          }
 | 
						|
        catch (IllegalAccessException ignore)
 | 
						|
          {
 | 
						|
          }
 | 
						|
        catch (InvocationTargetException exception)
 | 
						|
          {
 | 
						|
            Throwable cause = exception.getCause();
 | 
						|
            if (cause instanceof ObjectStreamException)
 | 
						|
              throw (ObjectStreamException) cause;
 | 
						|
            else if (cause instanceof RuntimeException)
 | 
						|
              throw (RuntimeException) cause;
 | 
						|
            else if (cause instanceof Error)
 | 
						|
              throw (Error) cause;
 | 
						|
          }
 | 
						|
      }
 | 
						|
 | 
						|
    if (this.resolveEnabled)
 | 
						|
      obj = resolveObject(obj);
 | 
						|
 | 
						|
    rememberHandle(obj, shared, handle);
 | 
						|
    if (!shared)
 | 
						|
      {
 | 
						|
        if (obj instanceof byte[])
 | 
						|
          return ((byte[]) obj).clone();
 | 
						|
        if (obj instanceof short[])
 | 
						|
          return ((short[]) obj).clone();
 | 
						|
        if (obj instanceof int[])
 | 
						|
          return ((int[]) obj).clone();
 | 
						|
        if (obj instanceof long[])
 | 
						|
          return ((long[]) obj).clone();
 | 
						|
        if (obj instanceof char[])
 | 
						|
          return ((char[]) obj).clone();
 | 
						|
        if (obj instanceof boolean[])
 | 
						|
          return ((boolean[]) obj).clone();
 | 
						|
        if (obj instanceof float[])
 | 
						|
          return ((float[]) obj).clone();
 | 
						|
        if (obj instanceof double[])
 | 
						|
          return ((double[]) obj).clone();
 | 
						|
        if (obj instanceof Object[])
 | 
						|
          return ((Object[]) obj).clone();
 | 
						|
      }
 | 
						|
    return obj;
 | 
						|
  }
 | 
						|
 | 
						|
  private void clearHandles()
 | 
						|
  {
 | 
						|
    handles.clear();
 | 
						|
    this.nextOID = baseWireHandle;
 | 
						|
  }
 | 
						|
 | 
						|
  private void readNextBlock() throws IOException
 | 
						|
  {
 | 
						|
    byte marker = this.realInputStream.readByte();
 | 
						|
    while (marker == TC_RESET)
 | 
						|
      {
 | 
						|
        if(dump) dumpElementln("RESET");
 | 
						|
        clearHandles();
 | 
						|
        marker = this.realInputStream.readByte();
 | 
						|
      }
 | 
						|
    readNextBlock(marker);
 | 
						|
  }
 | 
						|
 | 
						|
  private void readNextBlock(byte marker) throws IOException
 | 
						|
  {
 | 
						|
    if (marker == TC_BLOCKDATA)
 | 
						|
      {
 | 
						|
        if(dump) dumpElement("BLOCK DATA SIZE=");
 | 
						|
        this.blockDataBytes = this.realInputStream.readUnsignedByte();
 | 
						|
        if(dump) dumpElementln (Integer.toString(this.blockDataBytes));
 | 
						|
      }
 | 
						|
    else if (marker == TC_BLOCKDATALONG)
 | 
						|
      {
 | 
						|
        if(dump) dumpElement("BLOCK DATA LONG SIZE=");
 | 
						|
        this.blockDataBytes = this.realInputStream.readInt();
 | 
						|
        if(dump) dumpElementln (Integer.toString(this.blockDataBytes));
 | 
						|
      }
 | 
						|
    else
 | 
						|
      {
 | 
						|
        throw new EOFException("Attempt to read primitive data, but no data block is active.");
 | 
						|
      }
 | 
						|
 | 
						|
    if (this.blockData.length < this.blockDataBytes)
 | 
						|
      this.blockData = new byte[this.blockDataBytes];
 | 
						|
 | 
						|
    this.realInputStream.readFully (this.blockData, 0, this.blockDataBytes);
 | 
						|
    this.blockDataPosition = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  private void readArrayElements (Object array, Class clazz)
 | 
						|
    throws ClassNotFoundException, IOException
 | 
						|
  {
 | 
						|
    if (clazz.isPrimitive())
 | 
						|
      {
 | 
						|
        if (clazz == Boolean.TYPE)
 | 
						|
          {
 | 
						|
            boolean[] cast_array = (boolean[])array;
 | 
						|
            for (int i=0; i < cast_array.length; i++)
 | 
						|
              cast_array[i] = this.realInputStream.readBoolean();
 | 
						|
            return;
 | 
						|
          }
 | 
						|
        if (clazz == Byte.TYPE)
 | 
						|
          {
 | 
						|
            byte[] cast_array = (byte[])array;
 | 
						|
            for (int i=0; i < cast_array.length; i++)
 | 
						|
              cast_array[i] = this.realInputStream.readByte();
 | 
						|
            return;
 | 
						|
          }
 | 
						|
        if (clazz == Character.TYPE)
 | 
						|
          {
 | 
						|
            char[] cast_array = (char[])array;
 | 
						|
            for (int i=0; i < cast_array.length; i++)
 | 
						|
              cast_array[i] = this.realInputStream.readChar();
 | 
						|
            return;
 | 
						|
          }
 | 
						|
        if (clazz == Double.TYPE)
 | 
						|
          {
 | 
						|
            double[] cast_array = (double[])array;
 | 
						|
            for (int i=0; i < cast_array.length; i++)
 | 
						|
              cast_array[i] = this.realInputStream.readDouble();
 | 
						|
            return;
 | 
						|
          }
 | 
						|
        if (clazz == Float.TYPE)
 | 
						|
          {
 | 
						|
            float[] cast_array = (float[])array;
 | 
						|
            for (int i=0; i < cast_array.length; i++)
 | 
						|
              cast_array[i] = this.realInputStream.readFloat();
 | 
						|
            return;
 | 
						|
          }
 | 
						|
        if (clazz == Integer.TYPE)
 | 
						|
          {
 | 
						|
            int[] cast_array = (int[])array;
 | 
						|
            for (int i=0; i < cast_array.length; i++)
 | 
						|
              cast_array[i] = this.realInputStream.readInt();
 | 
						|
            return;
 | 
						|
          }
 | 
						|
        if (clazz == Long.TYPE)
 | 
						|
          {
 | 
						|
            long[] cast_array = (long[])array;
 | 
						|
            for (int i=0; i < cast_array.length; i++)
 | 
						|
              cast_array[i] = this.realInputStream.readLong();
 | 
						|
            return;
 | 
						|
          }
 | 
						|
        if (clazz == Short.TYPE)
 | 
						|
          {
 | 
						|
            short[] cast_array = (short[])array;
 | 
						|
            for (int i=0; i < cast_array.length; i++)
 | 
						|
              cast_array[i] = this.realInputStream.readShort();
 | 
						|
            return;
 | 
						|
          }
 | 
						|
      }
 | 
						|
    else
 | 
						|
      {
 | 
						|
        Object[] cast_array = (Object[])array;
 | 
						|
        for (int i=0; i < cast_array.length; i++)
 | 
						|
          cast_array[i] = readObject();
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  private void readFields (Object obj, ObjectStreamClass stream_osc)
 | 
						|
    throws ClassNotFoundException, IOException
 | 
						|
  {
 | 
						|
    ObjectStreamField[] fields = stream_osc.fieldMapping;
 | 
						|
 | 
						|
    for (int i = 0; i < fields.length; i += 2)
 | 
						|
      {
 | 
						|
        ObjectStreamField stream_field = fields[i];
 | 
						|
        ObjectStreamField real_field = fields[i + 1];
 | 
						|
        boolean read_value = (stream_field != null && stream_field.getOffset() >= 0 && stream_field.isToSet());
 | 
						|
        boolean set_value = (real_field != null && real_field.isToSet());
 | 
						|
        String field_name;
 | 
						|
        char type;
 | 
						|
 | 
						|
        if (stream_field != null)
 | 
						|
          {
 | 
						|
            field_name = stream_field.getName();
 | 
						|
            type = stream_field.getTypeCode();
 | 
						|
          }
 | 
						|
        else
 | 
						|
          {
 | 
						|
            field_name = real_field.getName();
 | 
						|
            type = real_field.getTypeCode();
 | 
						|
          }
 | 
						|
 | 
						|
        switch(type)
 | 
						|
          {
 | 
						|
          case 'Z':
 | 
						|
            {
 | 
						|
              boolean value =
 | 
						|
                read_value ? this.realInputStream.readBoolean() : false;
 | 
						|
              if (dump && read_value && set_value)
 | 
						|
                dumpElementln("  " + field_name + ": " + value);
 | 
						|
              if (set_value)
 | 
						|
                real_field.setBooleanField(obj, value);
 | 
						|
              break;
 | 
						|
            }
 | 
						|
          case 'B':
 | 
						|
            {
 | 
						|
              byte value =
 | 
						|
                read_value ? this.realInputStream.readByte() : 0;
 | 
						|
              if (dump && read_value && set_value)
 | 
						|
                dumpElementln("  " + field_name + ": " + value);
 | 
						|
              if (set_value)
 | 
						|
                real_field.setByteField(obj, value);
 | 
						|
              break;
 | 
						|
            }
 | 
						|
          case 'C':
 | 
						|
            {
 | 
						|
              char value =
 | 
						|
                read_value ? this.realInputStream.readChar(): 0;
 | 
						|
              if (dump && read_value && set_value)
 | 
						|
                dumpElementln("  " + field_name + ": " + value);
 | 
						|
              if (set_value)
 | 
						|
                real_field.setCharField(obj, value);
 | 
						|
              break;
 | 
						|
            }
 | 
						|
          case 'D':
 | 
						|
            {
 | 
						|
              double value =
 | 
						|
                read_value ? this.realInputStream.readDouble() : 0;
 | 
						|
              if (dump && read_value && set_value)
 | 
						|
                dumpElementln("  " + field_name + ": " + value);
 | 
						|
              if (set_value)
 | 
						|
                real_field.setDoubleField(obj, value);
 | 
						|
              break;
 | 
						|
            }
 | 
						|
          case 'F':
 | 
						|
            {
 | 
						|
              float value =
 | 
						|
                read_value ? this.realInputStream.readFloat() : 0;
 | 
						|
              if (dump && read_value && set_value)
 | 
						|
                dumpElementln("  " + field_name + ": " + value);
 | 
						|
              if (set_value)
 | 
						|
                real_field.setFloatField(obj, value);
 | 
						|
              break;
 | 
						|
            }
 | 
						|
          case 'I':
 | 
						|
            {
 | 
						|
              int value =
 | 
						|
                read_value ? this.realInputStream.readInt() : 0;
 | 
						|
              if (dump && read_value && set_value)
 | 
						|
                dumpElementln("  " + field_name + ": " + value);
 | 
						|
              if (set_value)
 | 
						|
                real_field.setIntField(obj, value);
 | 
						|
              break;
 | 
						|
            }
 | 
						|
          case 'J':
 | 
						|
            {
 | 
						|
              long value =
 | 
						|
                read_value ? this.realInputStream.readLong() : 0;
 | 
						|
              if (dump && read_value && set_value)
 | 
						|
                dumpElementln("  " + field_name + ": " + value);
 | 
						|
              if (set_value)
 | 
						|
                real_field.setLongField(obj, value);
 | 
						|
              break;
 | 
						|
            }
 | 
						|
          case 'S':
 | 
						|
            {
 | 
						|
              short value =
 | 
						|
                read_value ? this.realInputStream.readShort() : 0;
 | 
						|
              if (dump && read_value && set_value)
 | 
						|
                dumpElementln("  " + field_name + ": " + value);
 | 
						|
              if (set_value)
 | 
						|
                real_field.setShortField(obj, value);
 | 
						|
              break;
 | 
						|
            }
 | 
						|
          case 'L':
 | 
						|
          case '[':
 | 
						|
            {
 | 
						|
              Object value =
 | 
						|
                read_value ? readObject() : null;
 | 
						|
              if (set_value)
 | 
						|
                real_field.setObjectField(obj, value);
 | 
						|
              break;
 | 
						|
            }
 | 
						|
          default:
 | 
						|
            throw new InternalError("Invalid type code: " + type);
 | 
						|
          }
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  // Toggles writing primitive data to block-data buffer.
 | 
						|
  private boolean setBlockDataMode (boolean on)
 | 
						|
  {
 | 
						|
    boolean oldmode = this.readDataFromBlock;
 | 
						|
    this.readDataFromBlock = on;
 | 
						|
 | 
						|
    if (on)
 | 
						|
      this.dataInputStream = this.blockDataInput;
 | 
						|
    else
 | 
						|
      this.dataInputStream = this.realInputStream;
 | 
						|
    return oldmode;
 | 
						|
  }
 | 
						|
 | 
						|
  // returns a new instance of REAL_CLASS that has been constructed
 | 
						|
  // only to the level of CONSTRUCTOR_CLASS (a super class of REAL_CLASS)
 | 
						|
  private Object newObject (Class real_class, Constructor constructor)
 | 
						|
    throws ClassNotFoundException, IOException
 | 
						|
  {
 | 
						|
    if (constructor == null)
 | 
						|
        throw new InvalidClassException("Missing accessible no-arg base class constructor for " + real_class.getName());
 | 
						|
    try
 | 
						|
      {
 | 
						|
        return VMObjectInputStream.allocateObject(real_class, constructor.getDeclaringClass(), constructor);
 | 
						|
      }
 | 
						|
    catch (InstantiationException e)
 | 
						|
      {
 | 
						|
        throw (ClassNotFoundException) new ClassNotFoundException
 | 
						|
          ("Instance of " + real_class + " could not be created").initCause(e);
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  // runs all registered ObjectInputValidations in prioritized order
 | 
						|
  // on OBJ
 | 
						|
  private void invokeValidators() throws InvalidObjectException
 | 
						|
  {
 | 
						|
    try
 | 
						|
      {
 | 
						|
        Iterator<ValidatorAndPriority> it = currentObjectValidators.iterator();
 | 
						|
        while(it.hasNext())
 | 
						|
          {
 | 
						|
            ValidatorAndPriority vap = it.next();
 | 
						|
            ObjectInputValidation validator = vap.validator;
 | 
						|
            validator.validateObject();
 | 
						|
          }
 | 
						|
      }
 | 
						|
    finally
 | 
						|
      {
 | 
						|
        currentObjectValidators = null;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  private void callReadMethod (Method readObject, Class klass, Object obj)
 | 
						|
    throws ClassNotFoundException, IOException
 | 
						|
  {
 | 
						|
    try
 | 
						|
      {
 | 
						|
        readObject.invoke(obj, new Object[] { this });
 | 
						|
      }
 | 
						|
    catch (InvocationTargetException x)
 | 
						|
      {
 | 
						|
        /* Rethrow if possible. */
 | 
						|
        Throwable exception = x.getTargetException();
 | 
						|
        if (exception instanceof RuntimeException)
 | 
						|
          throw (RuntimeException) exception;
 | 
						|
        if (exception instanceof IOException)
 | 
						|
          throw (IOException) exception;
 | 
						|
        if (exception instanceof ClassNotFoundException)
 | 
						|
          throw (ClassNotFoundException) exception;
 | 
						|
 | 
						|
        throw (IOException) new IOException(
 | 
						|
          "Exception thrown from readObject() on " + klass).initCause(x);
 | 
						|
      }
 | 
						|
    catch (Exception x)
 | 
						|
      {
 | 
						|
        throw (IOException) new IOException(
 | 
						|
          "Failure invoking readObject() on " + klass).initCause(x);
 | 
						|
      }
 | 
						|
 | 
						|
    // Invalidate fields which has been read through readFields.
 | 
						|
    prereadFields = null;
 | 
						|
  }
 | 
						|
 | 
						|
  private static final int BUFFER_SIZE = 1024;
 | 
						|
 | 
						|
  private DataInputStream realInputStream;
 | 
						|
  private DataInputStream dataInputStream;
 | 
						|
  private DataInputStream blockDataInput;
 | 
						|
  private int blockDataPosition;
 | 
						|
  private int blockDataBytes;
 | 
						|
  private byte[] blockData;
 | 
						|
  private boolean useSubclassMethod;
 | 
						|
  private int nextOID;
 | 
						|
  private boolean resolveEnabled;
 | 
						|
  private Map<Integer,Pair<Boolean,Object>> handles;
 | 
						|
  private Object currentObject;
 | 
						|
  private ObjectStreamClass currentObjectStreamClass;
 | 
						|
  private TreeSet<ValidatorAndPriority> currentObjectValidators;
 | 
						|
  private boolean readDataFromBlock;
 | 
						|
  private boolean fieldsAlreadyRead;
 | 
						|
  private Hashtable<Class,ObjectStreamClass> classLookupTable;
 | 
						|
  private GetField prereadFields;
 | 
						|
 | 
						|
  private static boolean dump;
 | 
						|
 | 
						|
  // The nesting depth for debugging output
 | 
						|
  private int depth = 0;
 | 
						|
 | 
						|
  private static final boolean DEBUG = false;
 | 
						|
 | 
						|
  private void dumpElement (String msg)
 | 
						|
  {
 | 
						|
    System.out.print(msg);
 | 
						|
  }
 | 
						|
 | 
						|
  private void dumpElementln (String msg)
 | 
						|
  {
 | 
						|
    System.out.println(msg);
 | 
						|
    for (int i = 0; i < depth; i++)
 | 
						|
      System.out.print (" ");
 | 
						|
    System.out.print (Thread.currentThread() + ": ");
 | 
						|
  }
 | 
						|
 | 
						|
  private void dumpElementln (String msg, Object obj)
 | 
						|
  {
 | 
						|
    try
 | 
						|
      {
 | 
						|
        System.out.print(msg);
 | 
						|
        if (java.lang.reflect.Proxy.isProxyClass(obj.getClass()))
 | 
						|
          System.out.println(obj.getClass());
 | 
						|
        else
 | 
						|
        System.out.println(obj);
 | 
						|
      }
 | 
						|
    catch (Exception _)
 | 
						|
      {
 | 
						|
      }
 | 
						|
    for (int i = 0; i < depth; i++)
 | 
						|
      System.out.print (" ");
 | 
						|
    System.out.print (Thread.currentThread() + ": ");
 | 
						|
  }
 | 
						|
 | 
						|
  // used to keep a prioritized list of object validators
 | 
						|
  private static final class ValidatorAndPriority implements Comparable
 | 
						|
  {
 | 
						|
    int priority;
 | 
						|
    ObjectInputValidation validator;
 | 
						|
 | 
						|
    ValidatorAndPriority (ObjectInputValidation validator, int priority)
 | 
						|
    {
 | 
						|
      this.priority = priority;
 | 
						|
      this.validator = validator;
 | 
						|
    }
 | 
						|
 | 
						|
    public int compareTo (Object o)
 | 
						|
    {
 | 
						|
      ValidatorAndPriority vap = (ValidatorAndPriority)o;
 | 
						|
      return this.priority - vap.priority;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 |