mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			1967 lines
		
	
	
		
			57 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			1967 lines
		
	
	
		
			57 KiB
		
	
	
	
		
			Java
		
	
	
	
/* ObjectInputStream.java -- Class used to read serialized objects
 | 
						|
   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006
 | 
						|
   Free Software Foundation, Inc.
 | 
						|
 | 
						|
This file is part of GNU Classpath.
 | 
						|
 | 
						|
GNU Classpath is free software; you can redistribute it and/or modify
 | 
						|
it under the terms of the GNU General Public License as published by
 | 
						|
the Free Software Foundation; either version 2, or (at your option)
 | 
						|
any later version.
 | 
						|
 | 
						|
GNU Classpath is distributed in the hope that it will be useful, but
 | 
						|
WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
						|
General Public License for more details.
 | 
						|
 | 
						|
You should have received a copy of the GNU General Public License
 | 
						|
along with GNU Classpath; see the file COPYING.  If not, write to the
 | 
						|
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
						|
02110-1301 USA.
 | 
						|
 | 
						|
Linking this library statically or dynamically with other modules is
 | 
						|
making a combined work based on this library.  Thus, the terms and
 | 
						|
conditions of the GNU General Public License cover the whole
 | 
						|
combination.
 | 
						|
 | 
						|
As a special exception, the copyright holders of this library give you
 | 
						|
permission to link this library with independent modules to produce an
 | 
						|
executable, regardless of the license terms of these independent
 | 
						|
modules, and to copy and distribute the resulting executable under
 | 
						|
terms of your choice, provided that you also meet, for each linked
 | 
						|
independent module, the terms and conditions of the license of that
 | 
						|
module.  An independent module is a module which is not derived from
 | 
						|
or based on this library.  If you modify this library, you may extend
 | 
						|
this exception to your version of the library, but you are not
 | 
						|
obligated to do so.  If you do not wish to do so, delete this
 | 
						|
exception statement from your version. */
 | 
						|
 | 
						|
 | 
						|
package java.io;
 | 
						|
 | 
						|
import gnu.java.io.ObjectIdentityWrapper;
 | 
						|
 | 
						|
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.Hashtable;
 | 
						|
import java.util.Iterator;
 | 
						|
import java.util.TreeSet;
 | 
						|
import java.util.Vector;
 | 
						|
 | 
						|
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;
 | 
						|
    this.objectLookupTable = new Hashtable();
 | 
						|
    this.classLookupTable = new Hashtable();
 | 
						|
    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
 | 
						|
  {
 | 
						|
    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);
 | 
						|
      }
 | 
						|
    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.
 | 
						|
    * @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)
 | 
						|
     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 ");
 | 
						|
 	  Integer oid = new Integer(this.realInputStream.readInt());
 | 
						|
 	  if(dump) dumpElementln(Integer.toHexString(oid.intValue()));
 | 
						|
 	  ret_val = ((ObjectIdentityWrapper)
 | 
						|
 		     this.objectLookupTable.get(oid)).object;
 | 
						|
 	  break;
 | 
						|
 	}
 | 
						|
 	
 | 
						|
       case TC_CLASS:
 | 
						|
 	{
 | 
						|
 	  if(dump) dumpElementln("CLASS");
 | 
						|
 	  ObjectStreamClass osc = (ObjectStreamClass)readObject();
 | 
						|
 	  Class clazz = osc.forClass();
 | 
						|
 	  assignNewHandle(clazz);
 | 
						|
 	  ret_val = clazz;
 | 
						|
 	  break;
 | 
						|
 	}
 | 
						|
 	
 | 
						|
       case TC_PROXYCLASSDESC:
 | 
						|
 	{
 | 
						|
 	  if(dump) dumpElementln("PROXYCLASS");
 | 
						|
 	  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);
 | 
						|
                }
 | 
						|
            }
 | 
						|
 	  assignNewHandle(osc);
 | 
						|
 	  
 | 
						|
 	  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:
 | 
						|
       case TC_LONGSTRING:
 | 
						|
 	{
 | 
						|
 	  if(dump) dumpElement("STRING=");
 | 
						|
 	  String s = this.realInputStream.readUTF();
 | 
						|
 	  if(dump) dumpElementln(s);
 | 
						|
 	  ret_val = processResolution(null, s, assignNewHandle(s));
 | 
						|
 	  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);
 | 
						|
 	  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);
 | 
						|
 	  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);
 | 
						|
	      
 | 
						|
 	      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);
 | 
						|
              break;
 | 
						|
	      
 | 
						|
 	    } // end if (osc.realClassIsExternalizable)
 | 
						|
 	  
 | 
						|
 	  Object obj = newObject(clazz, osc.firstNonSerializableParentConstructor);
 | 
						|
 	  
 | 
						|
 	  int handle = assignNewHandle(obj);
 | 
						|
 	  Object prevObject = this.currentObject;
 | 
						|
 	  ObjectStreamClass prevObjectStreamClass = this.currentObjectStreamClass;
 | 
						|
	  TreeSet prevObjectValidators = this.currentObjectValidators;
 | 
						|
 	  
 | 
						|
 	  this.currentObject = obj;
 | 
						|
	  this.currentObjectValidators = null;
 | 
						|
 	  ObjectStreamClass[] hierarchy =
 | 
						|
 	    inputGetObjectStreamClasses(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);
 | 
						|
 			  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);
 | 
						|
	  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);
 | 
						|
 	}
 | 
						|
	
 | 
						|
       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);
 | 
						|
 | 
						|
    ClassLoader callersClassLoader = currentLoader();
 | 
						|
	      
 | 
						|
    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, callersClassLoader);
 | 
						|
      }
 | 
						|
	      
 | 
						|
    /* Now that fields have been read we may resolve the class
 | 
						|
     * (and read annotation if needed). */
 | 
						|
    Class clazz = resolveClass(osc);
 | 
						|
    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();
 | 
						|
    
 | 
						|
    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 VMObjectInputStream.currentClassLoader();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * 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 = (ObjectStreamClass)classLookupTable.get(clazz);
 | 
						|
    if (oclazz == null)
 | 
						|
      return ObjectStreamClass.lookup(clazz);
 | 
						|
    else
 | 
						|
      return oclazz;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Reconstruct class hierarchy the same way
 | 
						|
   * {@link java.io.ObjectStreamClass#getObjectStreamClasses(Class)} does
 | 
						|
   * but using lookupClass instead of ObjectStreamClass.lookup. This
 | 
						|
   * dup is necessary localize the lookup table. Hopefully some future
 | 
						|
   * rewritings will be able to prevent this.
 | 
						|
   *
 | 
						|
   * @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[] inputGetObjectStreamClasses(Class clazz)
 | 
						|
  {
 | 
						|
    ObjectStreamClass osc = lookupClass(clazz);
 | 
						|
 | 
						|
    if (osc == null)
 | 
						|
      return new ObjectStreamClass[0];
 | 
						|
    else
 | 
						|
      {
 | 
						|
        Vector oscs = new Vector();
 | 
						|
 | 
						|
        while (osc != null)
 | 
						|
          {
 | 
						|
            oscs.addElement(osc);
 | 
						|
            osc = osc.getSuper();
 | 
						|
	  }
 | 
						|
 | 
						|
        int count = oscs.size();
 | 
						|
	ObjectStreamClass[] sorted_oscs = new ObjectStreamClass[count];
 | 
						|
 | 
						|
        for (int i = count - 1; i >= 0; i--)
 | 
						|
          sorted_oscs[count - i - 1] = (ObjectStreamClass) oscs.elementAt(i);
 | 
						|
 | 
						|
        return sorted_oscs;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * 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.
 | 
						|
   * @return A valid handle for the specified object.
 | 
						|
   */
 | 
						|
  private int assignNewHandle(Object obj)
 | 
						|
  {
 | 
						|
    this.objectLookupTable.put(new Integer(this.nextOID),
 | 
						|
			       new ObjectIdentityWrapper(obj));
 | 
						|
    return this.nextOID++;
 | 
						|
  }
 | 
						|
 | 
						|
  private Object processResolution(ObjectStreamClass osc, Object obj, int handle)
 | 
						|
    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);
 | 
						|
 | 
						|
    this.objectLookupTable.put(new Integer(handle),
 | 
						|
			       new ObjectIdentityWrapper(obj));
 | 
						|
 | 
						|
    return obj;
 | 
						|
  }
 | 
						|
 | 
						|
  private void clearHandles()
 | 
						|
  {
 | 
						|
    this.objectLookupTable.clear();
 | 
						|
    this.nextOID = baseWireHandle;
 | 
						|
  }
 | 
						|
 | 
						|
  private void readNextBlock() throws IOException
 | 
						|
  {
 | 
						|
    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 it = currentObjectValidators.iterator();
 | 
						|
	while(it.hasNext())
 | 
						|
	  {
 | 
						|
	    ValidatorAndPriority vap = (ValidatorAndPriority) 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 Hashtable objectLookupTable;
 | 
						|
  private Object currentObject;
 | 
						|
  private ObjectStreamClass currentObjectStreamClass;
 | 
						|
  private TreeSet currentObjectValidators;
 | 
						|
  private boolean readDataFromBlock;
 | 
						|
  private boolean fieldsAlreadyRead;
 | 
						|
  private Hashtable 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() + ": ");
 | 
						|
  }
 | 
						|
 | 
						|
  // 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;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 |