home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / io / ObjectInputStream.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  71.8 KB  |  2,230 lines

  1. /*
  2.  * @(#)ObjectInputStream.java    1.65 98/03/18
  3.  *
  4.  * Copyright 1996-1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.io;
  16.  
  17. import java.util.Vector;
  18. import java.util.Stack;
  19. import java.util.Hashtable;
  20. import java.lang.Math;
  21. import java.lang.reflect.InvocationTargetException;
  22.  
  23. /**
  24.  * An ObjectInputStream deserializes primitive data and objects previously
  25.  * written using an ObjectOutputStream.
  26.  * 
  27.  * ObjectOutputStream and ObjectInputStream can provide an application
  28.  * with persistent storage for graphs of objects when used with a
  29.  * FileOutputStream and FileInputStream respectively.
  30.  * ObjectInputStream is used to recover those objects previously
  31.  * serialized. Other uses include passing objects between hosts using
  32.  * a socket stream or for marshaling and unmarshaling arguments and
  33.  * parameters in a remote communication system.<p>
  34.  *
  35.  * ObjectInputStream ensures that the types of all objects in the
  36.  * graph created from the stream match the classes present in the
  37.  * Java Virtual Machine.  Classes are loaded as required using the
  38.  * standard mechanisms. <p>
  39.  *
  40.  * Only objects that support the java.io.Serializable or
  41.  * java.io.Externalizable interface can be read from streams.
  42.  *
  43.  * The method <STRONG>readObject</STRONG> is used to read an object
  44.  * from the stream.  Java's safe casting should be used to get the
  45.  * desired type.  In Java, strings and arrays are objects and are
  46.  * treated as objects during serialization. When read they need to be
  47.  * cast to the expected type.<p>
  48.  *
  49.  * Primitive data types can be read from the stream using the appropriate
  50.  * method on DataInput. <p>
  51.  * 
  52.  * The default deserialization mechanism for objects restores the
  53.  * contents of each field to the value and type it had when it was written.
  54.  * Fields declared as transient or static are ignored by the
  55.  * deserialization process.  References to other objects cause those
  56.  * objects to be read from the stream as necessary.  Graphs of objects
  57.  * are restored correctly using a reference sharing mechanism.  New
  58.  * objects are always allocated when deserializing, which prevents
  59.  * existing objects from being overwritten. <p>
  60.  *
  61.  * Reading an object is analogous to running the constructors of a new
  62.  * object.  Memory is allocated for the object and initialized to zero
  63.  * (NULL).  No-arg constructors are invoked for the non-serializable
  64.  * classes and then the fields of the serializable classes are
  65.  * restored from the stream starting with the serializable class closest to
  66.  * java.lang.object and finishing with the object's most specifiec
  67.  * class. <p>
  68.  *
  69.  * For example to read from a stream as written by the example in
  70.  * ObjectOutputStream: <br>
  71.  *
  72.  * <PRE>
  73.  *    FileInputStream istream = new FileInputStream("t.tmp");
  74.  *    ObjectInputStream p = new ObjectInputStream(istream);
  75.  *
  76.  *    int i = p.readInt();
  77.  *    String today = (String)p.readObject();
  78.  *    Date date = (Date)p.readObject();
  79.  *
  80.  *    istream.close();
  81.  * </PRE>
  82.  *
  83.  * Classes control how they are serialized by implementing either the
  84.  * java.io.Serializable or java.io.Externalizable interfaces.<P>
  85.  *
  86.  * Implementing the Serializable interface allows object serialization
  87.  * to save and restore the entire state of the object and it allows
  88.  * classes to evolve between the time the stream is written and the time it is
  89.  * read.  It automatically traverses references between objects,
  90.  * saving and restoring entire graphs.
  91.  *
  92.  * Serializable classes that require special handling during the
  93.  * serialization and deserialization process should implement both
  94.  * of these methods:<p>
  95.  *
  96.  * <PRE>
  97.  * private void writeObject(java.io.ObjectOutputStream stream)
  98.  *     throws IOException;
  99.  * private void readObject(java.io.ObjectInputStream stream)
  100.  *     throws IOException, ClassNotFoundException; 
  101.  * </PRE><p>
  102.  *
  103.  * The readObject method is responsible for reading and restoring the
  104.  * state of the object for its particular class using data written to
  105.  * the stream by the corresponding writeObject method.  The method
  106.  * does not need to concern itself with the state belonging to its
  107.  * superclasses or subclasses.  State is restored by reading data from
  108.  * the ObjectInputStream for the individual fields and making
  109.  * assignments to the appropriate fields of the object.  Reading
  110.  * primitive data types is supported by DataInput. <p>
  111.  *
  112.  * Serialization does not read or assign values to the fields of any
  113.  * object that does not implement the java.io.Serializable interface.
  114.  * Subclasses of Objects that are not serializable can be
  115.  * serializable. In this case the non-serializable class must have a
  116.  * no-arg constructor to allow its fields to be initialized.  In this
  117.  * case it is the responsibility of the subclass to save and restore
  118.  * the state of the non-serializable class. It is frequently the case that
  119.  * the fields of that class are accessible (public, package, or
  120.  * protected) or that there are get and set methods that can be used
  121.  * to restore the state. <p>
  122.  *
  123.  * Any exception that occurs while deserializing an object will be
  124.  * caught by the ObjectInputStream and abort the reading process. <p>
  125.  *
  126.  * Implementing the Externalizable interface allows the object to
  127.  * assume complete control over the contents and format of the object's
  128.  * serialized form.  The methods of the Externalizable interface,
  129.  * writeExternal and readExternal, are called to save and restore the
  130.  * objects state.  When implemented by a class they can write and read
  131.  * their own state using all of the methods of ObjectOutput and
  132.  * ObjectInput.  It is the responsibility of the objects to handle any
  133.  * versioning that occurs.
  134.  *
  135.  * @author  Roger Riggs
  136.  * @version 1.65, 03/18/98
  137.  * @see java.io.DataInput
  138.  * @see java.io.ObjectOutputStream
  139.  * @see java.io.Serializable
  140.  * @since   JDK1.1
  141.  */
  142. public class ObjectInputStream extends InputStream
  143.     implements ObjectInput, ObjectStreamConstants
  144.     /**
  145.      * Create an ObjectInputStream that reads from the specified InputStream.
  146.      * The stream header containing the magic number and version number
  147.      * are read from the stream and verified. This method will block
  148.      * until the corresponding ObjectOutputStream has written and flushed the header.
  149.      * @exception StreamCorruptedException The version or magic number are incorrect.
  150.      * @exception IOException An exception occurred in the underlying stream.
  151.      */
  152.     public ObjectInputStream(InputStream in)
  153.     throws IOException, StreamCorruptedException
  154.     {
  155.         enableSubclassImplementation = false;
  156.       /*
  157.        * Save the input stream to read bytes from
  158.        * Create a DataInputStream used to read primitive types.
  159.        * Setup the DataInputStream to read from this ObjectInputStream
  160.        */
  161.     this.in = in;
  162.     dis  = new DataInputStream(this); 
  163.     readStreamHeader();
  164.     resetStream();
  165.     }
  166.  
  167.     /**
  168.      * Provide a way for subclasses that are completely reimplementing
  169.      * ObjectInputStream to not have to allocate private data just used by
  170.      * this implementation of ObjectInputStream.
  171.      *
  172.      * Add the following line to the security policy file to enable
  173.      * subclassing.
  174.      *
  175.      * <PRE>
  176.      *        permission SerializablePermission "enableSubclassImplementation" ;
  177.      * </PRE><p>
  178.      *
  179.      *
  180.      * @exception IOException   Thrown if not called by a subclass.
  181.      * @exception SecurityException if subclass does not have 
  182.      *                 SerializablePermission "enableSubclassImplementation".
  183.      */
  184.     protected ObjectInputStream() throws IOException, SecurityException {
  185.     SecurityManager sm = System.getSecurityManager();
  186.     if (sm != null) sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
  187.     enableSubclassImplementation = true;
  188.     }
  189.  
  190.     /**
  191.      * Read an object from the ObjectInputStream.
  192.      * The class of the object, the signature of the class, and the values
  193.      * of the non-transient and non-static fields of the class and all
  194.      * of its supertypes are read.  Default deserializing for a class can be
  195.      * overriden using the writeObject and readObject methods.
  196.      * Objects referenced by this object are read transitively so
  197.      * that a complete equivalent graph of objects is reconstructed by 
  198.      * readObject. <p>
  199.      *
  200.      * The root object is completly restored when all of its fields
  201.      * and the objects it references are completely restored.  At this
  202.      * point the object validation callbacks are executed in order
  203.      * based on their registered priorities. The callbacks are
  204.      * registered by objects (in the readObject special methods)
  205.      * as they are individually restored.
  206.      *
  207.      * Exceptions are thrown for problems with the InputStream and for classes
  208.      * that should not be deserialized.  All exceptions are fatal to the 
  209.      * InputStream and leave it in an indeterminate state; it is up to the 
  210.      * caller to ignore or recover the stream state.
  211.      * @exception java.lang.ClassNotFoundException Class of a serialized object
  212.      *      cannot be found.
  213.      * @exception InvalidClassException Something is wrong with a class used by
  214.      *     serialization.
  215.      * @exception StreamCorruptedException Control information in the
  216.      *     stream is inconsistent.
  217.      * @exception OptionalDataException Primitive data was found in the 
  218.      * stream instead of objects.
  219.      * @exception IOException Any of the usual Input/Output related exceptions.
  220.      */
  221.     public final Object readObject()
  222.     throws OptionalDataException, ClassNotFoundException, IOException {
  223.     if (enableSubclassImplementation)
  224.         return readObjectOverride();
  225.     else {
  226.  
  227.         /* require local Class for object by default. */
  228.         return readObject(true);
  229.     }
  230.     }
  231.  
  232.     /**
  233.      * This method is called by trusted subclasses of ObjectOutputStream
  234.      * that constructed ObjectOutputStream using the 
  235.      * protected no-arg constructor. The subclass is expected to provide
  236.      * an override method with the modifier "final".
  237.      *
  238.      * @return the Object read from the stream.
  239.      *
  240.      * @see #ObjectInputStream()
  241.      * @see #readObject
  242.      * @since JDK 1.2
  243.      */
  244.     protected Object readObjectOverride()
  245.      throws OptionalDataException, ClassNotFoundException, IOException 
  246.     {
  247.     return null;
  248.     }
  249.  
  250.     /*
  251.      * Private implementation of Read an object from the ObjectInputStream.
  252.      *
  253.      * @param requireLocalClass If false, do not throw ClassNotFoundException
  254.      *                          when local class does not exist.
  255.      *
  256.      * @since     JDK1.2
  257.      */
  258.     /* This method should be private. JDK 1.1.4 compiler fails if it is private.
  259.      * When JDK 1.1.4 is no longer used for bootstrapping, make this private.
  260.      * (Worked with pre-FCS JDK 1.1.5 and JDK 1.2 beta1.)
  261.      */
  262.     final Object readObject(boolean requireLocalClass)
  263.     throws OptionalDataException, ClassNotFoundException, IOException
  264.     {
  265.     /* If the stream is in blockData mode and there's any data
  266.      * left throw an exception to report how much there is.
  267.      */
  268.     if (blockDataMode) {
  269.         /* Can't use member method available() since it depends on the unreliable
  270.          *  method InputStream.available().
  271.          */
  272.         if (count == 0)
  273.         refill();
  274.         if (count > 0)
  275.         throw new OptionalDataException(count);
  276.     }
  277.     
  278.     /*
  279.      * Look ahead now to absorb any pending reset's.
  280.      * Before changing the state.
  281.      */
  282.     peekCode();
  283.  
  284.     /* Save the current state and get ready to read an object. */
  285.     Object prevObject = currentObject;
  286.     ObjectStreamClass prevClass = currentClassDesc;
  287.     boolean prevBlockDataMode = setBlockData(false);
  288.     
  289.     recursionDepth++;    // Entering
  290.     Object obj = null;
  291.  
  292.     /* 
  293.      * Check for reset, handle it before reading an object.
  294.      */
  295.  
  296.     byte rcode;
  297.     rcode = readCode();
  298.     try {
  299.         /*
  300.          * Dispatch on the next code in the stream.
  301.          */
  302.         int wireoffset = -1;
  303.  
  304.         switch (rcode) {
  305.         
  306.         case TC_NULL:
  307.         obj = null;
  308.         break;
  309.         
  310.         case TC_REFERENCE: 
  311.         /* This is a reference to a pre-existing object */
  312.         wireoffset = readInt() - baseWireHandle; 
  313.         
  314.         try {
  315.             obj = wireHandle2Object.elementAt(wireoffset);
  316.         } catch (ArrayIndexOutOfBoundsException e) {
  317.             throw new StreamCorruptedException("Reference to object never serialized.");
  318.         }
  319.         break;
  320.         
  321.         case TC_STRING:
  322.         {
  323.             obj = readUTF(); 
  324.             Object localObj = obj;
  325.             wireoffset = assignWireOffset(obj);
  326.             /* Allow subclasses to replace the object */
  327.             if (enableResolve) {
  328.             obj = resolveObject(obj);
  329.             }
  330.  
  331.             if (obj != localObj)
  332.             wireHandle2Object.setElementAt(obj, wireoffset);
  333.         }
  334.         break;
  335.         
  336.         case TC_CLASS:
  337.         ObjectStreamClass v =
  338.             (ObjectStreamClass)readObject(requireLocalClass);
  339.         if (v == null) {
  340.             /*
  341.              * No class descriptor in stream or class not serializable
  342.              */
  343.             throw new StreamCorruptedException("Class not in stream");
  344.         }
  345.         obj = v.forClass();
  346.         if (obj == null && requireLocalClass) {
  347.             throw new ClassNotFoundException(v.getName());
  348.         }
  349.         assignWireOffset(obj);
  350.         break;
  351.         
  352.         case TC_CLASSDESC:
  353.         obj = inputClassDescriptor();
  354.         break;
  355.         
  356.         case TC_ARRAY:
  357.         wireoffset = inputArray(requireLocalClass);
  358.         obj = currentObject;
  359.         /* Allow subclasses to replace the object */
  360.         if (enableResolve) {
  361.             obj = resolveObject(obj);
  362.         }
  363.  
  364.         if (obj != currentObject)
  365.             wireHandle2Object.setElementAt(obj, wireoffset);
  366.         break;
  367.         
  368.         case TC_OBJECT:
  369.         wireoffset = inputObject(requireLocalClass);
  370.         obj = currentObject;
  371.  
  372.         /* Allow the object to resolve itself. */
  373.         if (obj instanceof Resolvable) {
  374.             obj = ((Resolvable)obj).readResolve();
  375.         }
  376.  
  377.         /* Allow subclasses to replace the object */
  378.         if (enableResolve) {
  379.             obj = resolveObject(obj);
  380.         }
  381.  
  382.         if (obj != currentObject)
  383.             wireHandle2Object.setElementAt(obj, wireoffset);
  384.         break;
  385.         
  386.         case TC_ENDBLOCKDATA:
  387.         if (!prevBlockDataMode)
  388.             throw new StreamCorruptedException("Unexpected end of block data");
  389.         pushbackCode(TC_ENDBLOCKDATA);
  390.         count = -1;    /* Flag EOF */ 
  391.         throw new OptionalDataException(true);
  392.         
  393.         case TC_BLOCKDATA:
  394.         case TC_BLOCKDATALONG:
  395.         if (rcode == TC_BLOCKDATALONG) { /* long block: 32 bit size */
  396.             int b3 = in.read();
  397.             int b2 = in.read();
  398.             int b1 = in.read();
  399.             int b0 = in.read();
  400.             if ((b3 | b2 | b1 | b0) < 0)
  401.             throw new StreamCorruptedException("EOF expecting count");
  402.             count = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
  403.             if (count < 0)
  404.             throw new StreamCorruptedException("Negative block data size");
  405.         } else {            /* normal block: 8 bit size */
  406.             count = in.read();
  407.             if (count < 0)
  408.             throw new StreamCorruptedException("EOF expecting count");
  409.         }
  410.  
  411.             if (!prevBlockDataMode)
  412.             throw new StreamCorruptedException("Unexpected blockdata");
  413.         
  414.         throw new OptionalDataException(count);
  415.         
  416.         case TC_EXCEPTION:
  417.         /* An exception happened during writing, reset the
  418.          * stream, read the exception, reset the stream and
  419.          * throw a writeAbortedException with the exception
  420.          * that was read.
  421.          */
  422.         resetStream();
  423.         IOException ee = (IOException)readObject();
  424.         resetStream();
  425.         throw new WriteAbortedException("Writing aborted by exception", ee);
  426.  
  427.         default:
  428.         throw new StreamCorruptedException("Unknown code in readObject " + rcode);
  429.         }
  430.     } catch (OptionalDataException optdata) {
  431.         /* OptionalDataExceptions won't terminate everything.
  432.          * so just rethrow it.
  433.          */
  434.         throw optdata;
  435.     } catch(IOException ee) {
  436.         if (abortIOException == null && abortClassNotFoundException == null)
  437.         abortIOException = ee;
  438.     } catch(ClassNotFoundException ee) {
  439.         if (abortIOException == null && abortClassNotFoundException == null)
  440.         abortClassNotFoundException = ee;
  441.     } finally {
  442.         recursionDepth --;
  443.         currentObject = prevObject;
  444.         currentClassDesc = prevClass;
  445.         setBlockData(prevBlockDataMode);
  446.     }
  447.     
  448.     /* Check for thrown exceptions and re-throw them, clearing them if
  449.      * this is the last recursive call .
  450.      */
  451.     IOException exIOE = abortIOException;
  452.     if (recursionDepth == 0)
  453.         abortIOException = null;
  454.     if (exIOE != null)
  455.         throw exIOE;
  456.  
  457.     
  458.     ClassNotFoundException exCNF = abortClassNotFoundException;
  459.     if (recursionDepth == 0)
  460.         abortClassNotFoundException = null;
  461.     if (exCNF != null) {
  462.         throw exCNF;
  463.     }
  464.     
  465.     // Check if this is the last nested read, if so
  466.     // Call the validations
  467.     if (recursionDepth == 0) {
  468.         doValidations();
  469.     }
  470.  
  471.     return obj;
  472.     }
  473.  
  474.     /**
  475.      * Read the non-static and non-transient fields of the current class
  476.      * from this stream.  This may only be called from the readObject method
  477.      * of the class being deserialized. It will throw the NotActiveException
  478.      * if it is called otherwise.
  479.      *
  480.      * @exception java.lang.ClassNotFoundException if the class of a serialized
  481.      *              object could not be found.
  482.      * @exception IOException        if an I/O error occurs.
  483.      * @exception NotActiveException if the stream is not currently reading
  484.      *              objects.
  485.      */
  486.     public void defaultReadObject()
  487.     throws IOException, ClassNotFoundException, NotActiveException
  488.     {
  489.     if (currentObject == null || currentClassDesc == null)
  490.         throw new NotActiveException("defaultReadObject");
  491.  
  492.     ObjectStreamField[] fields = 
  493.         currentClassDesc.getFieldsNoCopy();
  494.     if (fields.length > 0) {
  495.         boolean prevmode = setBlockData(false);
  496.         inputClassFields(currentObject, currentClass, fields);
  497.         setBlockData(prevmode);
  498.     }
  499.     }
  500.     
  501.     /**
  502.      * Reads the persistent fields from the stream and makes them 
  503.      * available by name.
  504.      * 
  505.      * @exception java.lang.ClassNotFoundException if the class of a serialized
  506.      *              object could not be found.
  507.      * @exception IOException        if an I/O error occurs.
  508.      * @exception NotActiveException if the stream is not currently reading
  509.      *              objects.
  510.      * @since JDK 1.2
  511.      */
  512.     public ObjectInputStream.GetField readFields()
  513.         throws IOException, ClassNotFoundException, NotActiveException
  514.     {
  515.     if (currentObject == null || currentClassDesc == null)
  516.         throw new NotActiveException("defaultReadObject");
  517.  
  518.     // TBD: Interlock w/ defaultReadObject
  519.  
  520.     GetFieldImpl curr = new GetFieldImpl(currentClassDesc);
  521.     currentGetFields = curr;
  522.     boolean prevmode = setBlockData(false);
  523.     curr.read(this);
  524.     setBlockData(prevmode);
  525.     return curr;
  526.     }
  527.  
  528.     /**
  529.      * Register an object to be validated before the graph is
  530.      * returned.  While similar to resolveObject these validations are
  531.      * called after the entire graph has been reconstituted.
  532.      * Typically, a readObject method will register the object with
  533.      * the stream so that when all of the objects are restored a final
  534.      * set of validations can be performed.
  535.      * @param obj the object to receive the validation callback.
  536.      * @param prio controls the order of callbacks;zero is a good default.
  537.      * Use higher numbers to be called back earlier, lower numbers for later
  538.      * callbacks. Within a priority, callbacks are processed in no
  539.      * particular order.
  540.      *
  541.      * @exception NotActiveException The stream is not currently reading 
  542.      * objects so it is invalid to register a callback.
  543.      * @exception InvalidObjectException The validation object is null.
  544.      */
  545.     public synchronized void registerValidation(ObjectInputValidation obj,
  546.                         int prio)
  547.     throws NotActiveException, InvalidObjectException
  548.     {
  549.     if (recursionDepth == 0) {
  550.         throw new NotActiveException("readObject not Active");
  551.     }
  552.     if (obj == null) {
  553.         throw new InvalidObjectException("Null is not a valid callback object");
  554.     }
  555.  
  556.     ValidationCallback cb = new ValidationCallback(obj, prio);
  557.  
  558.     if (callbacks == null) {
  559.         callbacks = new Vector(100,100);
  560.     }
  561.     // insert at the end if the priority is less than or equal to
  562.     // the last element.
  563.     if (callbacks.isEmpty() ||
  564.         ((ValidationCallback)(callbacks.lastElement())).priority >= prio) {
  565.         callbacks.addElement(cb);
  566.         return;
  567.     }
  568.  
  569.     // search for the element with priority that is <= to the new
  570.     // priority, insert before it. 
  571.     int size = callbacks.size();
  572.     for (int i = 0; i < size; i++) {
  573.         ValidationCallback curr = (ValidationCallback)callbacks.elementAt(i);
  574.         if (curr.priority <= prio) {
  575.         callbacks.insertElementAt(cb, i);
  576.         break;
  577.         }
  578.     }
  579.     }
  580.  
  581.     /*
  582.      * If any validations are pending, do them and cleanup the validation vector
  583.      * if an exception is raised, it is passed on to abort the deserialization.
  584.      */
  585.     private void doValidations() throws InvalidObjectException {
  586.     if (callbacks == null)
  587.         return;
  588.     
  589.     int size = callbacks.size();
  590.     for (int i = 0; i < size; i++) {
  591.         ValidationCallback curr = (ValidationCallback)callbacks.elementAt(i);
  592.         curr.callback.validateObject();
  593.     }
  594.     callbacks.setSize(0);
  595.     }
  596.  
  597.     /**
  598.      * Subclasses may implement this method to allow classes to be
  599.      * fetched from an alternate source. 
  600.      *
  601.      * The corresponding method in ObjectOutputStream is
  602.      * annotateClass.  This method will be invoked only once for each
  603.      * unique class in the stream.  This method can be implemented by
  604.      * subclasses to use an alternate loading mechanism but must
  605.      * return a Class object.  Once returned, the serialVersionUID of the
  606.      * class is compared to the serialVersionUID of the serialized class.
  607.      * If there is a mismatch, the deserialization fails and an exception
  608.      * is raised. <p>
  609.      *
  610.      * By default the class name is resolved relative to the class
  611.      * that called readObject. <p>
  612.      *
  613.      * @exception ClassNotFoundException If class of
  614.      * a serialized object cannot be found.
  615.      */
  616.     protected Class resolveClass(ObjectStreamClass v)
  617.     throws IOException, ClassNotFoundException
  618.     {
  619.     /* Resolve by looking up the stack for a non-zero class
  620.      * loader. If not found use the system class loader.
  621.      */
  622.     return loadClass0(null, v.getName());
  623.     }
  624.  
  625.     /* Resolve a class name relative to the specified class.  If the
  626.      * class is null find the first available class loader up the
  627.      * stack.  This will resolve classes relative to the caller of
  628.      * ObjectInputStream instead of the itself. Classes must be
  629.      * loaded/resolved relative to the application.
  630.      */
  631.     private native Class loadClass0(Class cl, String classname)
  632.     throws ClassNotFoundException;
  633.  
  634.     /**
  635.      * This method will allow trusted subclasses of ObjectInputStream
  636.      * to substitute one object for another during
  637.      * deserialization. Replacing objects is disabled until
  638.      * enableResolveObject is called. The enableResolveObject method
  639.      * checks that the stream requesting to resolve object can be
  640.      * trusted. Every reference to serializable objects is passed to
  641.      * resolveObject.  To insure that the private state of objects is
  642.      * not unintentionally exposed only trusted streams may use
  643.      * resolveObject. <p>
  644.      *
  645.      * This method is called after an object has been read but before it is
  646.      * returned from readObject.  The default resolveObject method
  647.      * just returns the new object. <p>
  648.      *
  649.      * When a subclass is replacing objects it must insure that the
  650.      * substituted object is compatible with every field where the
  651.      * reference will be stored.  Objects whose type is not a subclass
  652.      * of the type of the field or array element abort the
  653.      * serialization by raising an exception and the object is not be
  654.      * stored. <p>
  655.      *
  656.      * This method is called only once when each object is first encountered.
  657.      * All subsequent references to the object will be redirected to the
  658.      * new object. <P>
  659.      *
  660.      * @exception IOException Any of the usual Input/Output exceptions.
  661.      */
  662.     protected Object resolveObject(Object obj)
  663.         throws IOException
  664.     {
  665.     return obj;
  666.     }
  667.  
  668.  
  669.     /**
  670.      * Enable the stream to allow objects read from the stream to be replaced.
  671.      * If the stream is a trusted class it is allowed to enable replacment.
  672.      * 
  673.      * When enabled the resolveObject method is called for every object
  674.      * being deserialized.
  675.      *
  676.      * Add the following line to the security policy file to enable
  677.      * resolveObject() to be overriden by the subclass of ObjectInputStream.
  678.      *
  679.      *        permission SerializablePermission "enableSubstitution" ;
  680.      * 
  681.      * @exception java.lang.SecurityException
  682.      *            if SerializablePermission "enableSubstitution" is not 
  683.      *            allowed by the security policy.
  684.      */
  685.     protected boolean enableResolveObject(boolean enable)
  686.     throws SecurityException
  687.     {
  688.     boolean previous = enableResolve;
  689.     if (enable) {
  690.         SecurityManager sm = System.getSecurityManager();
  691.         if (sm != null) sm.checkPermission(SUBSTITUTION_PERMISSION);
  692.         enableResolve = true;
  693.     } else {
  694.         enableResolve = false;
  695.     }
  696.     return previous;
  697.     }
  698.  
  699.  
  700.     /**
  701.      * The readStreamHeader method is provided to allow subclasses to
  702.      * read and verify their own stream headers. It reads and
  703.      * verifies the magic number and version number.
  704.      */
  705.     protected void readStreamHeader()
  706.     throws IOException, StreamCorruptedException
  707.     {
  708.     short incoming_magic = readShort();
  709.     short incoming_version = readShort();
  710.     if (incoming_magic != STREAM_MAGIC)
  711.         throw new StreamCorruptedException("InputStream does not contain a serialized object");
  712.     
  713.     if (incoming_version != STREAM_VERSION)
  714.         throw new StreamCorruptedException("Version Mismatch, Expected " +
  715.                            STREAM_VERSION + " and got " +
  716.                            incoming_version);
  717.     }
  718.  
  719.     /*
  720.      * Read a ObjectStreamClass from the stream, it may recursively
  721.      * create other ObjectStreamClasses for the classes it references.
  722.      */
  723.     private ObjectStreamClass inputClassDescriptor()
  724.     throws IOException, InvalidClassException, ClassNotFoundException
  725.     {
  726.  
  727.     /* Read the class name and hash */
  728.     Class aclass;
  729.     String classname = readUTF(); 
  730.     long hash = readLong();
  731.  
  732.     /* Read a new class version descriptor from the stream */
  733.     ObjectStreamClass v = new ObjectStreamClass(classname, hash);
  734.  
  735.     /* Assign the wire handle for this ObjectStreamClass and read it */
  736.     int wireoffset = assignWireOffset(v); 
  737.     v.read(this);
  738.  
  739.     /* Switch to BlockDataMode and call resolveClass.
  740.      * It may raise ClassNotFoundException.
  741.      * Consume any extra data or objects left by resolve class and
  742.      * read the endOfBlockData. Then switch out of BlockDataMode.
  743.      */
  744.     boolean prevMode = setBlockData(true);
  745.     try {
  746.         aclass = resolveClass((ObjectStreamClass)v);
  747.     } catch (ClassNotFoundException e) {
  748.         /* if the most derived class, this exception will be thrown at a later time. */
  749.         aclass = null;
  750.     } catch (NoClassDefFoundError e) {
  751.         /* This exception was thrown when looking for an array of class,
  752.          * and class could not be found.
  753.          */
  754.         aclass = null;
  755.     }
  756.     SkipToEndOfBlockData();
  757.     prevMode = setBlockData(prevMode);
  758.  
  759.  
  760.     /* Verify that the class returned is "compatible" with
  761.      * the class description.  i.e. the name and hash match.
  762.      * Set the class this ObjectStreamClass will use to create 
  763.      * instances.
  764.      */
  765.     v.setClass(aclass);
  766.  
  767.     /* Get the superdescriptor of this one and it set it.
  768.      */
  769.     ObjectStreamClass superdesc = (ObjectStreamClass)readObject();
  770.     v.setSuperclass(superdesc);
  771.  
  772.     return v;
  773.     }
  774.  
  775.     /* Private routine to read in an array. Called from inputObject
  776.      * after the typecode has been read from the stream.
  777.      */
  778.     private int inputArray(boolean requireLocalClass)
  779.     throws IOException, ClassNotFoundException
  780.     {
  781.     /* May raise ClassNotFoundException */
  782.     ObjectStreamClass v = (ObjectStreamClass)readObject();
  783.     
  784.     Class arrayclass = v.forClass();
  785.     if (arrayclass == null && requireLocalClass)
  786.         throw new ClassNotFoundException(v.getName());
  787.  
  788.     /* This can't be done with new because only the top level array
  789.      * is needed and the type must be set properly.
  790.      * the lower level arrays will be created when they are read.
  791.      */
  792.     int length = readInt();
  793.         currentObject = (arrayclass == null) ?
  794.         null : allocateNewArray(arrayclass, length);
  795.     int wireoffset = assignWireOffset(currentObject);
  796.     
  797.     /* Read in the values from the array,
  798.      * It dispatches using the type and read using the read* methods.
  799.      */
  800.     int i;
  801.     if (arrayclass != null
  802.         && arrayclass.getComponentType().isPrimitive()) {
  803.         Class type = arrayclass.getComponentType();
  804.         /* Arrays of primitive types read data in blocks and
  805.          * decode the data types from the buffer.
  806.              */
  807.         if (buffer == null)
  808.         buffer = new byte[1024];
  809.         int offset = buffer.length;
  810.         int buflen = buffer.length;
  811.  
  812.         if (type == Boolean.TYPE) {
  813.         boolean[] array = (boolean[])currentObject;
  814.         for (i = 0; i < length; i++) {
  815.             if (offset >= buflen) {
  816.             int readlen = Math.min(length-i, buflen);
  817.             readFully(buffer, 0, readlen);
  818.             offset = 0;
  819.             }
  820.             array[i] = (buffer[offset] != 0);
  821.             offset += 1;
  822.         }
  823.         } else if (type == Byte.TYPE) {
  824.         byte[] array = (byte[])currentObject;
  825.         readFully(array, 0, length);
  826.         } else if (type == Short.TYPE) {
  827.         short[] array = (short[])currentObject;
  828.         for (i = 0; i < length; i++) {
  829.             if (offset > buflen - 2) {
  830.             int readlen = Math.min((length-i)*2, buflen);
  831.             readFully(buffer, 0, readlen);
  832.             offset = 0;
  833.             }
  834.             array[i] = (short)(((buffer[offset] & 0xff) << 8) +
  835.                        ((buffer[offset+1] & 0xff) << 0));
  836.             offset += 2;
  837.         }
  838.         } else if (type == Integer.TYPE) {
  839.         int[] array = (int[])currentObject;
  840.         for (i = 0; i < length; i++) {
  841.             if (offset > buflen - 4) {
  842.             int readlen = Math.min((length-i)*4, buflen);
  843.             readFully(buffer, 0, readlen);
  844.             offset = 0;
  845.             }
  846.             array[i] = (((buffer[offset] & 0xff) << 24) +
  847.                 ((buffer[offset+1] & 0xff) << 16) +
  848.                 ((buffer[offset+2] & 0xff) << 8) +
  849.                 ((buffer[offset+3] & 0xff) << 0));
  850.             offset += 4;
  851.         }
  852.         } else if (type == Long.TYPE) {
  853.         long[] array = (long[])currentObject;
  854.         for (i = 0; i < length; i++) {
  855.             if (offset > buflen - 8) {
  856.             int readlen = Math.min((length-i)*8, buflen);
  857.             readFully(buffer, 0, readlen);
  858.             offset = 0;
  859.             }
  860.             int upper = (((buffer[offset] & 0xff) << 24) +
  861.                  ((buffer[offset+1] & 0xff) << 16) +
  862.                  ((buffer[offset+2] & 0xff) << 8) +
  863.                  ((buffer[offset+3] & 0xff) << 0));
  864.             int lower = (((buffer[offset+4] & 0xff) << 24) +
  865.                  ((buffer[offset+5] & 0xff) << 16) +
  866.                  ((buffer[offset+6] & 0xff) << 8) +
  867.                  ((buffer[offset+7] & 0xff) << 0));
  868.             array[i] = ((long)upper << 32) + ((long)lower & 0xFFFFFFFFL);
  869.             offset += 8;
  870.         }
  871.         } else if (type == Float.TYPE) {
  872.         float[] array = (float[])currentObject;
  873.         for (i = 0; i < length; i++) {
  874.             if (offset > buflen - 4) {
  875.             int readlen = Math.min((length-i)*4, buflen);
  876.             readFully(buffer, 0, readlen);
  877.             offset = 0;
  878.             }
  879.             int value = (((buffer[offset] & 0xff) << 24) +
  880.                  ((buffer[offset+1] & 0xff) << 16) +
  881.                  ((buffer[offset+2] & 0xff) << 8) +
  882.                  ((buffer[offset+3] & 0xff) << 0));
  883.             offset += 4;
  884.             array[i] = Float.intBitsToFloat(value);
  885.         }
  886.         } else if (type == Double.TYPE) {
  887.         double[] array = (double[])currentObject;
  888.         for (i = 0; i < length; i++) {
  889.             if (offset > buflen - 8) {
  890.             int readlen = Math.min((length-i)*8, buflen);
  891.             readFully(buffer, 0, readlen);
  892.             offset = 0;
  893.             }
  894.             int upper = (((buffer[offset] & 0xff) << 24) +
  895.                  ((buffer[offset+1] & 0xff) << 16) +
  896.                  ((buffer[offset+2] & 0xff) << 8) +
  897.                  ((buffer[offset+3] & 0xff) << 0));
  898.             int lower = (((buffer[offset+4] & 0xff) << 24) +
  899.                  ((buffer[offset+5] & 0xff) << 16) +
  900.                  ((buffer[offset+6] & 0xff) << 8) +
  901.                  ((buffer[offset+7] & 0xff) << 0));
  902.             offset += 8;
  903.             array[i] = Double.longBitsToDouble((((long)upper) << 32) +
  904.                                (lower & 0xFFFFFFFFL));
  905.         }
  906.         } else if (type == Character.TYPE) {
  907.         char[] array = (char[])currentObject;
  908.         for (i = 0; i < length; i++) {
  909.             if (offset > buflen - 2) {
  910.             int readlen = Math.min((length-i)*2, buflen);
  911.             readFully(buffer, 0, readlen);
  912.             offset = 0;
  913.             }
  914.             array[i] = (char)(((buffer[offset] & 0xff) << 8) +
  915.                       ((buffer[offset+1] & 0xff) << 0));
  916.             offset += 2;
  917.         }
  918.         } else {
  919.         throw new InvalidClassException(arrayclass.getName());
  920.         }
  921.     } else {        // Is array of objects
  922.         Object[] array = (Object[])currentObject;
  923.         boolean requiresLocalClass = (arrayclass != null);
  924.         for (i = 0; i < length; i++) {
  925.         Object obj = readObject(requiresLocalClass);
  926.         if (array != null)
  927.             array[i] = obj;
  928.         }
  929.     }
  930.  
  931.     return wireoffset;
  932.     }
  933.  
  934.     /*
  935.      * Read an instance of a class from the stream
  936.      * The new object typecode has already been read and used to dispatch to here.
  937.      * The ObjectStreamClass for the class is read and the class
  938.      * of the object retrieved from it.
  939.      * A new object is created of the specified class and
  940.      * each serializable class is processed using either
  941.      * the default serialization methods or class defined special methods
  942.      * if they have been defined.
  943.      * The handle for the object is returned, the object itself is in currentObject.
  944.      */
  945.     private int inputObject(boolean requireLocalClass)
  946.     throws IOException, ClassNotFoundException
  947.     {
  948.     int handle = -1;
  949.     /*
  950.      * Get the descriptor and then class of the incoming object.
  951.      */
  952.     currentClassDesc = (ObjectStreamClass)readObject();
  953.     currentClass = currentClassDesc.forClass();
  954.     if (currentClass == null && requireLocalClass)
  955.         throw new ClassNotFoundException(currentClassDesc.getName());
  956.     
  957.     
  958.     /* If Externalizable,
  959.      *  Create an instance and tell it to read its data.
  960.      * else,
  961.      *  Handle it as a serializable class.
  962.      */
  963.     if (currentClassDesc.isExternalizable()) {
  964.         try {
  965.         currentObject = (currentClass == null) ?
  966.                       null : allocateNewObject(currentClass, currentClass);
  967.         handle = assignWireOffset(currentObject);
  968.         boolean prevmode = blockDataMode;
  969.         try {
  970.             if (currentClassDesc.hasExternalizableBlockDataMode()) {
  971.             prevmode = setBlockData(true);
  972.             }
  973.  
  974.             if (currentObject != null) {
  975.             Externalizable ext = (Externalizable)currentObject;
  976.             ext.readExternal(this);
  977.             }
  978.         } finally {
  979.             if (currentClassDesc.hasExternalizableBlockDataMode()) {
  980.             SkipToEndOfBlockData();
  981.             setBlockData(prevmode);
  982.             }
  983.         }
  984.         } catch (NoSuchMethodError e) {
  985.         throw new InvalidClassException(currentClass.getName(),
  986.                         "NoSuchMethodError accessing no-arg constructor");
  987.         } catch (IllegalAccessException e) {
  988.         throw new InvalidClassException(currentClass.getName(),
  989.                         "IllegalAccessException");
  990.         } catch (InstantiationException e) {
  991.         throw new InvalidClassException(currentClass.getName(),
  992.                         "InstantiationException");
  993.         }
  994.     } else {
  995.         /* Count number of classes and descriptors we might have
  996.          * to work on.
  997.          */
  998.         ObjectStreamClass currdesc = currentClassDesc;
  999.         Class currclass = currentClass;
  1000.  
  1001.         int spBase = spClass;    // current top of stack
  1002.  
  1003.         /* The object's classes should be processed from supertype to subtype
  1004.          * Push all the clases of the current object onto a stack.
  1005.          * Note that only the serializable classes are represented
  1006.          * in the descriptor list. 
  1007.          *
  1008.          * Handle versioning where one or more supertypes of
  1009.          * have been inserted or removed.  The stack will
  1010.          * contain pairs of descriptors and the corresponding
  1011.          * class.  If the object has a class that did not occur in
  1012.          * the original the descriptor will be null.  If the
  1013.          * original object had a descriptor for a class not
  1014.          * present in the local hierarchy of the object the class will be
  1015.          * null.
  1016.          *
  1017.          */
  1018.  
  1019.         /*
  1020.          * This is your basic diff pattern, made simpler
  1021.          * because reordering is not allowed.
  1022.          */
  1023.         for (currdesc = currentClassDesc, currclass = currentClass;
  1024.          currdesc != null;
  1025.          currdesc = currdesc.getSuperclass()) {
  1026.  
  1027.         /*
  1028.          * Search the classes to see if the class of this
  1029.          * descriptor appears further up the hierarchy. Until
  1030.          * it's found assume its an inserted class.  If it's
  1031.          * not found, its the descriptor's class that has been
  1032.          * removed.
  1033.          */
  1034.         Class cc = currdesc.forClass();
  1035.         Class cl;
  1036.         for (cl = currclass; cl != null; cl = cl.getSuperclass()) {
  1037.             if (cc == cl) {
  1038.             // found a superclass that matches this descriptor
  1039.             break;
  1040.             } else {
  1041.             /* Ignore a class that doesn't match.  No
  1042.              * action is needed since it is already
  1043.              * initialized.
  1044.              */
  1045.             }
  1046.         }
  1047.         /* Test if there is room for this new entry.
  1048.          * If not, double the size of the arrays and copy the contents.
  1049.          */
  1050.         spClass++;
  1051.         if (spClass >= classes.length) {
  1052.             int newlen = classes.length * 2;
  1053.             Class[] newclasses = new Class[newlen];
  1054.             ObjectStreamClass[] newclassdesc = new ObjectStreamClass[newlen];
  1055.  
  1056.             System.arraycopy(classes, 0,
  1057.                  newclasses, 0,
  1058.                  classes.length);
  1059.             System.arraycopy(classdesc, 0,
  1060.                      newclassdesc, 0,
  1061.                      classes.length);
  1062.  
  1063.             classes = newclasses;
  1064.             classdesc = newclassdesc;
  1065.         }
  1066.  
  1067.         if (cl == null) {
  1068.             /* Class not found corresponding to this descriptor.
  1069.              * Pop off all the extra classes pushed.
  1070.              * Push the descriptor and a null class.
  1071.              */
  1072.             classdesc[spClass] = currdesc;
  1073.             classes[spClass] = null;
  1074.         } else {
  1075.                    /* Current class descriptor matches current class.
  1076.              * Some classes may have been inserted.
  1077.              * Record the match and advance the class, continue
  1078.              * with the next descriptor.
  1079.              */
  1080.             classdesc[spClass] = currdesc;
  1081.             classes[spClass] = cl;
  1082.             currclass = cl.getSuperclass();
  1083.         }
  1084.         }
  1085.  
  1086.         /* Allocate a new object.  The object is only constructed
  1087.          * above the highest serializable class and is set to
  1088.          * default values for all more specialized classes.
  1089.          * Remember the next wirehandle goes with the new object
  1090.          */
  1091.         try {
  1092.         currentObject = (currentClass == null) ?
  1093.                          null : allocateNewObject(currentClass, currclass);
  1094.         } catch (NoSuchMethodError e) {
  1095.         throw new InvalidClassException(currclass.getName(),
  1096.                         "NoSuchMethodError accessing no-arg constructor");
  1097.         } catch (IllegalAccessException e) {
  1098.         throw new InvalidClassException(currclass.getName(),
  1099.                         "IllegalAccessException");
  1100.         } catch (InstantiationException e) {
  1101.         throw new InvalidClassException(currclass.getName(),
  1102.                         "InstantiationException");
  1103.         }
  1104.         handle = assignWireOffset(currentObject);
  1105.         
  1106.         /* 
  1107.          * For all the pushed descriptors and classes.
  1108.          * If there is a descriptor but no class, skip the
  1109.          * data for that class.
  1110.          * If there is a class but no descriptor, just advance,
  1111.          * The classes fields have already been initialized to default
  1112.          * values.
  1113.          * Otherwise, there is both a descriptor and class,
  1114.          *     if the class has its own writeObject and readObject methods
  1115.          *        set blockData = true; and call the readObject method
  1116.          *    else
  1117.          *        invoke the defaultReadObject method
  1118.          *    if the stream was written by class specific methods
  1119.          *        skip any remaining data a objects until TC_ENDBLOCKDATA
  1120.          * Avoid setting BlockData=true unless necessary becase it flushes
  1121.          * the buffer.
  1122.          */
  1123.         try {
  1124.         for (spClass = spClass; spClass > spBase; spClass--) {
  1125.             /*
  1126.              * Set current descriptor and corresponding class
  1127.              */
  1128.             currentClassDesc = classdesc[spClass];
  1129.             currentClass = classes[spClass];
  1130.  
  1131.             if (classes[spClass] != null) {
  1132.             /* Read the data from the stream described by the
  1133.              * descriptor and store into the matching class.
  1134.              */
  1135.             setBlockData(true);    /* any reads are from datablocks */
  1136.             ObjectStreamClass localDesc = currentClassDesc.localClassDescriptor();
  1137.             if (!invokeObjectReader(currentObject, currentClass)) {
  1138.                 defaultReadObject();
  1139.             }
  1140.             } else {
  1141.             /* No local class for this descriptor,
  1142.              * Skip over the data for this class.
  1143.              * like defaultReadObject with a null currentObject.
  1144.              * The code will read the values but discard them.
  1145.              */
  1146.             ObjectStreamField[] fields = 
  1147.                 currentClassDesc.getFieldsNoCopy();
  1148.             if (fields.length > 0) {
  1149.                 boolean prevmode = setBlockData(false);
  1150.                 inputClassFields(null, currentClass, fields);
  1151.                 setBlockData(prevmode);
  1152.             }
  1153.             }
  1154.  
  1155.             /*
  1156.              * If the source class (stream) had a write object method
  1157.              * it may have written more data and will have written the
  1158.              * TC_ENDBLOCKDATA.  Skip anything up to that and read it.
  1159.              */
  1160.             if (currentClassDesc.hasWriteObject()) {
  1161.             SkipToEndOfBlockData();
  1162.             }
  1163.             setBlockData(false);
  1164.         }
  1165.         } finally {
  1166.         // Make sure we exit at the same stack level as when we started.
  1167.         spClass = spBase;
  1168.         }
  1169.     }
  1170.     return handle;
  1171.     }
  1172.  
  1173.     /*
  1174.      * Skip any unread block data and objects up to the next
  1175.      * TC_ENDBLOCKDATA.  Anybody can do this because readObject
  1176.      * handles the details of reporting if there is data left.
  1177.      * Try reading objects.  If it throws optional data
  1178.      * skip over it and try again. 
  1179.      */
  1180.     private void SkipToEndOfBlockData()
  1181.     throws IOException, ClassNotFoundException
  1182.     {
  1183.     while (peekCode() != TC_ENDBLOCKDATA) {
  1184.         try {
  1185.  
  1186.         /* do not require a local Class equivalent of object being read.*/
  1187.         Object ignore = readObject(false);
  1188.         } catch (OptionalDataException data) {
  1189.         if (data.length > 0)
  1190.             skip(data.length);
  1191.         }
  1192.     }
  1193.     readCode();            /* Consume TC_ENDBLOCKDATA */
  1194.     }
  1195.     
  1196.     /*
  1197.      * Reset the stream to be just like it was after the constructor.
  1198.      */
  1199.     private void resetStream() throws IOException {
  1200.     if (wireHandle2Object == null)
  1201.         wireHandle2Object = new Vector(100,100);
  1202.     else
  1203.         wireHandle2Object.setSize(0);   // release all references.
  1204.     nextWireOffset = 0;
  1205.  
  1206.     if (classes == null)
  1207.         classes = new Class[20];
  1208.     else {
  1209.         for (int i = 0; i < classes.length; i++)
  1210.         classes[i] = null;
  1211.     }
  1212.     if (classdesc == null)
  1213.         classdesc = new ObjectStreamClass[20];
  1214.     else {
  1215.         for (int i = 0; i < classdesc.length; i++)
  1216.         classdesc[i] = null;
  1217.     }
  1218.     spClass = 0;
  1219.  
  1220.     setBlockData(true);        // Re-enable buffering
  1221.     if (callbacks != null)
  1222.         callbacks.setSize(0);    // discard any pending callbacks
  1223.     }
  1224.  
  1225.     /* Allocate a handle for an object.
  1226.      * The Vector is indexed by the wireHandleOffset
  1227.      * and contains the object.
  1228.      */
  1229.     private int assignWireOffset(Object obj)
  1230.     throws IOException
  1231.     {
  1232.     wireHandle2Object.addElement(obj);
  1233.     if (++nextWireOffset != wireHandle2Object.size())
  1234.       throw new StreamCorruptedException(
  1235.           "Elements not assigned in order");
  1236.     return nextWireOffset-1;
  1237.     }
  1238.  
  1239.     /*
  1240.      * Peek at the next control code in the stream.
  1241.      * If the code has not been peeked at yet, read it from the stream.
  1242.      */
  1243.     private byte peekCode() throws IOException, StreamCorruptedException{
  1244.     while (currCode == 0) {
  1245.  
  1246.         int newcode = in.read();    // Read byte from the underlying stream
  1247.         if (newcode < 0) 
  1248.         throw new EOFException("Expecting code");
  1249.         
  1250.         currCode = (byte)newcode;
  1251.         if (currCode < TC_BASE || currCode > TC_MAX)
  1252.         throw new StreamCorruptedException("Type code out of range, is " + currCode);
  1253.  
  1254.         /* 
  1255.          * Handle reset as a hidden code and reset the stream.
  1256.          */
  1257.         if (currCode == TC_RESET) {
  1258.         if (recursionDepth != 0 ||
  1259.             currentObject != null ||
  1260.             currentClassDesc != null)
  1261.             throw new StreamCorruptedException("Illegal stream state for reset");
  1262.         
  1263.         /* Reset the stream, and repeat the peek at the next code
  1264.          */
  1265.         resetStream();
  1266.         currCode = 0;
  1267.         }
  1268.     }
  1269.     return currCode;
  1270.     }
  1271.     
  1272.     /*
  1273.      * Return the next control code in the stream.
  1274.      * peekCode gets the next code.  readCode just consumes it.
  1275.      */
  1276.     private byte readCode()
  1277.     throws IOException, StreamCorruptedException
  1278.     {
  1279.     byte tc = peekCode();
  1280.     currCode = 0;
  1281.     return tc;
  1282.     }
  1283.     
  1284.     /*
  1285.      * Put back the specified code to be peeked at next time.
  1286.      */
  1287.     private void pushbackCode(byte code) {
  1288.     currCode = code;
  1289.     }
  1290.     /* -----------------------------------------------------*/
  1291.     /*
  1292.      * Implement the InputStream methods.  The stream has
  1293.      * two modes used internally to ObjectInputStream.  When
  1294.      * in BlockData mode, all reads are only from datablocks
  1295.      * as original written. End of data (-1) is returned
  1296.      * if something other than a datablock is next in the stream.
  1297.      * When not in BlockData mode (false), reads pass directly
  1298.      * through to the underlying stream.
  1299.      * The BlockData mode is used to encapsulate data written
  1300.      * by class specific writeObject methods that is intended
  1301.      * only to be read by corresponding readObject method of the 
  1302.      * same class.  The blocking of data allows it to be skipped
  1303.      * if necessary.
  1304.      *
  1305.      * The setBlockData method is used to switch buffering
  1306.      * on and off.  When switching between on and off 
  1307.      * there must be no data pending to be read. This is 
  1308.      * an internal consistency check that will throw an exception. 
  1309.      *
  1310.      */
  1311.     private InputStream in;
  1312.  
  1313.     /*
  1314.      * Count of bytes available from blockData, if zero, call refill
  1315.      * to look for more.  If -1 always return eof (-1)
  1316.      */
  1317.     private int count;
  1318.         
  1319.     private boolean blockDataMode;
  1320.  
  1321.     private byte[] buffer;    // buffer for reading array data
  1322.  
  1323.     /*
  1324.      * Set the blockdata buffering mode.
  1325.      * If it is being set to false after being true there must
  1326.      * be no pending data. If count > 0 a corrupted exception is thrown.
  1327.      */
  1328.     private boolean setBlockData(boolean mode) throws IOException {
  1329.     if (blockDataMode == mode)
  1330.         return mode;
  1331.     if (blockDataMode && count > 0)
  1332.         throw new StreamCorruptedException("Unread data");
  1333.  
  1334.     /* Set count to allow reading or not */
  1335.     count =  mode ? 0 : -1;
  1336.  
  1337.     blockDataMode = mode;
  1338.     return !mode;
  1339.     }
  1340.     
  1341.     /**
  1342.      * Reads a byte of data. This method will block if no input is 
  1343.      * available.
  1344.      * @return     the byte read, or -1 if the end of the
  1345.      *        stream is reached.
  1346.      * @exception IOException If an I/O error has occurred.
  1347.      */
  1348.     public int read() throws IOException {
  1349.     int data;
  1350.     if (blockDataMode) {
  1351.         while (count == 0)
  1352.         refill();
  1353.         if (count < 0)
  1354.         return -1;            /* EOF */
  1355.         data = in.read();
  1356.         if (data >= 0)
  1357.         count--;
  1358.     } else {
  1359.         data = in.read();        /* read directly from input stream */
  1360.     }
  1361.     return data;
  1362.     }
  1363.  
  1364.     /*
  1365.      * Expect the next thing in the stream is a datablock, If its a
  1366.      * datablock, extract the count of bytes to allow.  If data is not
  1367.      * available set the count to zero.  On error or EOF, set count to -1.
  1368.      */
  1369.     private void refill() throws IOException {
  1370.     count = -1;        /*  No more data to read, EOF */
  1371.     byte code;
  1372.     try {
  1373.         code = peekCode();
  1374.     } catch (EOFException e) {
  1375.         return;
  1376.     }
  1377.     if (code == TC_BLOCKDATA) {
  1378.         code = readCode();            /* Consume the code */
  1379.         int c = in.read();
  1380.         if (c < 0)
  1381.         throw new StreamCorruptedException("EOF expecting count");
  1382.         
  1383.         count = c & 0xff;
  1384.     } else if (code == TC_BLOCKDATALONG) {
  1385.         code = readCode();
  1386.         int b3 = in.read();
  1387.         int b2 = in.read();
  1388.         int b1 = in.read();
  1389.         int b0 = in.read();
  1390.         if ((b3 | b2 | b1 | b0) < 0)
  1391.         throw new StreamCorruptedException("EOF expecting count");
  1392.         int c = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
  1393.         /*
  1394.          * The 32 bit integer size in the long block data format is
  1395.          * signed (unlike like the normal block data format), and
  1396.          * negative values are invalid.
  1397.          */
  1398.         if (c < 0)
  1399.         throw new StreamCorruptedException("Negative block data size");
  1400.  
  1401.         count = c;
  1402.     }
  1403.     }
  1404.     
  1405.     /**
  1406.      * Reads into an array of bytes.  This method will
  1407.      * block until some input is available. Consider
  1408.      * using java.io.DataInputStream.readFully to read exactly
  1409.      * 'length' bytes.
  1410.      * @param b    the buffer into which the data is read
  1411.      * @param off the start offset of the data
  1412.      * @param len the maximum number of bytes read
  1413.      * @return  the actual number of bytes read, -1 is
  1414.      *         returned when the end of the stream is reached.
  1415.      * @exception IOException If an I/O error has occurred.
  1416.      * @see java.io.DataInputStream#readFully(byte[],int,int)
  1417.      */
  1418.     public int read(byte[] data, int offset, int length) throws IOException {
  1419.     int v;
  1420.     int i;
  1421.  
  1422.     if (length < 0)
  1423.         throw new IndexOutOfBoundsException();
  1424.  
  1425.     if (blockDataMode) {
  1426.         while (count == 0)
  1427.         refill();
  1428.         if (count < 0)
  1429.         return -1;
  1430.         int l = Math.min(length, count);
  1431.         i = in.read(data, offset, l);
  1432.         if (i > 0)
  1433.         count -= i;
  1434.         return i;            /* return number of bytes read */
  1435.     } else {
  1436.         /* read directly from input stream */
  1437.         return in.read(data, offset, length);
  1438.     }
  1439.     }
  1440.  
  1441.     /**
  1442.      * Returns the number of bytes that can be read without blocking.
  1443.      * @return the number of available bytes.
  1444.      */
  1445.     public int available() throws IOException {
  1446.     /*
  1447.      * If in blockdataMode returns the number of bytes in the
  1448.      * current block. If that is zero, it will try to read
  1449.      * another blockdata from the stream if any data is available from the
  1450.      * underlying stream..
  1451.      * If not in blockdata mode it returns zero.
  1452.      */
  1453.     if (blockDataMode) {
  1454.         if (count == 0 && in.available() > 0)
  1455.         refill();
  1456.         if (count >= 0) {
  1457.         return count;
  1458.         } else
  1459.         return 0;    /* EOF is no bytes available */
  1460.     } else {
  1461.         return 0;        /* Not blockdata, no bytes available */
  1462.     }
  1463.     }
  1464.  
  1465.     /**
  1466.      * Closes the input stream. Must be called
  1467.      * to release any resources associated with
  1468.      * the stream.
  1469.      * @exception IOException If an I/O error has occurred.
  1470.      */
  1471.     public void close() throws IOException {
  1472.     in.close();
  1473.     }
  1474.  
  1475.     /* -----------------------------------------------------*/
  1476.     /*
  1477.      * Provide the methods to implement DataInput.
  1478.      * They delegate to an Instance of DataInputStream that
  1479.      * reads its input from the ObjectInputStream.
  1480.      * This allows this stream to manage the blocked data the data
  1481.      * as necessary.
  1482.      */
  1483.     private DataInputStream dis;
  1484.     
  1485.     /**
  1486.      * Reads in a boolean.
  1487.      * @return the boolean read.
  1488.      * @exception EOFException If end of file is reached.
  1489.      * @exception IOException If other I/O error has occurred.
  1490.      */
  1491.     public boolean readBoolean() throws IOException {
  1492.     return dis.readBoolean();
  1493.     }
  1494.  
  1495.     /**
  1496.      * Reads an 8 bit byte.
  1497.      * @return the 8 bit byte read.
  1498.      * @exception EOFException If end of file is reached.
  1499.      * @exception IOException If other I/O error has occurred.
  1500.      */
  1501.     public byte readByte() throws IOException  {
  1502.     return dis.readByte();
  1503.     }
  1504.  
  1505.     /**
  1506.      * Reads an unsigned 8 bit byte.
  1507.      * @return the 8 bit byte read.
  1508.      * @exception EOFException If end of file is reached.
  1509.      * @exception IOException If other I/O error has occurred.
  1510.      */
  1511.     public int readUnsignedByte()  throws IOException {
  1512.     return dis.readUnsignedByte();
  1513.     }
  1514.  
  1515.     /**
  1516.      * Reads a 16 bit short.
  1517.      * @return the 16 bit short read.
  1518.      * @exception EOFException If end of file is reached.
  1519.      * @exception IOException If other I/O error has occurred.
  1520.      */
  1521.     public short readShort()  throws IOException {
  1522.     return dis.readShort();
  1523.     }
  1524.  
  1525.     /**
  1526.      * Reads an unsigned 16 bit short.
  1527.      * @return the 16 bit short read.
  1528.      * @exception EOFException If end of file is reached.
  1529.      * @exception IOException If other I/O error has occurred.
  1530.      */
  1531.     public int readUnsignedShort() throws IOException {
  1532.     return dis.readUnsignedShort();
  1533.     }
  1534.  
  1535.     /**
  1536.      * Reads a 16 bit char.
  1537.      * @return the 16 bit char read. 
  1538.      * @exception EOFException If end of file is reached.
  1539.      * @exception IOException If other I/O error has occurred.
  1540.      */
  1541.     public char readChar()  throws IOException {
  1542.     return dis.readChar();
  1543.     }
  1544.  
  1545.     /**
  1546.      * Reads a 32 bit int.
  1547.      * @return the 32 bit integer read.
  1548.      * @exception EOFException If end of file is reached.
  1549.      * @exception IOException If other I/O error has occurred.
  1550.      */
  1551.     public int readInt()  throws IOException {
  1552.     return dis.readInt();
  1553.     }
  1554.  
  1555.     /**
  1556.      * Reads a 64 bit long.
  1557.      * @return the read 64 bit long.
  1558.      * @exception EOFException If end of file is reached.
  1559.      * @exception IOException If other I/O error has occurred.
  1560.      */
  1561.     public long readLong()  throws IOException {
  1562.     return dis.readLong();
  1563.     }
  1564.  
  1565.     /**
  1566.      * Reads a 32 bit float.
  1567.      * @return the 32 bit float read.
  1568.      * @exception EOFException If end of file is reached.
  1569.      * @exception IOException If other I/O error has occurred.
  1570.      */
  1571.     public float readFloat() throws IOException {
  1572.     return dis.readFloat();
  1573.     }
  1574.  
  1575.     /**
  1576.      * Reads a 64 bit double.
  1577.      * @return the 64 bit double read.
  1578.      * @exception EOFException If end of file is reached.
  1579.      * @exception IOException If other I/O error has occurred.
  1580.      */
  1581.     public double readDouble() throws IOException {
  1582.     return dis.readDouble();
  1583.     }
  1584.  
  1585.     /**
  1586.      * Reads bytes, blocking until all bytes are read.
  1587.      * @param b    the buffer into which the data is read
  1588.      * @exception EOFException If end of file is reached.
  1589.      * @exception IOException If other I/O error has occurred.
  1590.      */
  1591.     public void readFully(byte[] data) throws IOException {
  1592.     dis.readFully(data);
  1593.     }
  1594.  
  1595.     /**
  1596.      * Reads bytes, blocking until all bytes are read.
  1597.      * @param b    the buffer into which the data is read
  1598.      * @param off the start offset of the data
  1599.      * @param len the maximum number of bytes to read
  1600.      * @exception EOFException If end of file is reached.
  1601.      * @exception IOException If other I/O error has occurred.
  1602.      */
  1603.     public void readFully(byte[] data, int offset, int size) throws IOException {
  1604.     if (size < 0)
  1605.         throw new IndexOutOfBoundsException();
  1606.     
  1607.     dis.readFully(data, offset, size);
  1608.     }
  1609.  
  1610.     /**
  1611.      * Skips bytes, block until all bytes are skipped.
  1612.      * @param n the number of bytes to be skipped
  1613.      * @return    the actual number of bytes skipped.
  1614.      * @exception EOFException If end of file is reached.
  1615.      * @exception IOException If other I/O error has occurred.
  1616.      */
  1617.     public int skipBytes(int len) throws IOException {
  1618.     return dis.skipBytes(len);
  1619.     }
  1620.  
  1621.     /**
  1622.      * Reads in a line that has been terminated by a \n, \r, 
  1623.      * \r\n or EOF.
  1624.      * @return a String copy of the line.
  1625.      * @deprecated This method does not properly convert bytes to characters.
  1626.      * see DataInputStream for the details and alternatives.
  1627.      */
  1628.     public String readLine() throws IOException {
  1629.     return dis.readLine();
  1630.     }
  1631.  
  1632.     /**
  1633.      * Reads a UTF format String.
  1634.      * @return the String.
  1635.      */
  1636.      public String readUTF() throws IOException {
  1637.     return dis.readUTF();
  1638.     }
  1639.     
  1640.     /*
  1641.      * Invoke the readObject method if present
  1642.      */
  1643.     private boolean invokeObjectReader(Object obj, Class aclass)
  1644.     throws InvalidClassException, StreamCorruptedException,
  1645.         ClassNotFoundException, IOException
  1646.     {
  1647.     if (currentClassDesc.readObjectMethod == null)
  1648.         return false;
  1649.  
  1650.     try {
  1651.         Object[] args = new Object[1];
  1652.         args[0] = this;
  1653.  
  1654.         currentClassDesc.readObjectMethod.invoke(obj, args);
  1655.         return true;
  1656.     } catch (InvocationTargetException e) {
  1657.         Throwable t = e.getTargetException();
  1658.         if (t instanceof ClassNotFoundException)
  1659.         throw (ClassNotFoundException)t;
  1660.         else if (t instanceof IOException)
  1661.         throw (IOException)t;
  1662.         else if (t instanceof RuntimeException)
  1663.         throw (RuntimeException) t;
  1664.         else if (t instanceof Error)
  1665.         throw (Error) t;
  1666.         else
  1667.         throw new Error("interal error");
  1668.     } catch (IllegalAccessException e) {
  1669.         return false;
  1670.     }
  1671.     }
  1672.  
  1673.     /*
  1674.      * Read the fields of the specified class from the input stream and set
  1675.      * the values of the fields in the specified object. If the specified
  1676.      * object is null, just consume the fields without setting any values. If
  1677.      * any ObjectStreamField does not have a reflected Field, don't try to set
  1678.      * that field in the object.
  1679.      */
  1680.     private void inputClassFields(Object o, Class cl,
  1681.                   ObjectStreamField[] fields) 
  1682.     throws InvalidClassException, StreamCorruptedException,
  1683.         ClassNotFoundException, IOException
  1684.     {
  1685.     int primFields = fields.length - currentClassDesc.objFields;
  1686.  
  1687.     /*
  1688.      * Read and dispatch primitive data fields from the input
  1689.      * stream.
  1690.      */
  1691.       if (currentClassDesc.primBytes > 0) {
  1692.         if (data == null) {
  1693.         data = new byte[Math.max(currentClassDesc.primBytes,
  1694.                      INITIAL_BUFFER_SIZE)];
  1695.         } else if (data.length < currentClassDesc.primBytes) {
  1696.         data = new byte[currentClassDesc.primBytes];
  1697.         }
  1698.         readFully(data, 0, currentClassDesc.primBytes);
  1699.     }
  1700.  
  1701.     if (o != null) {
  1702.         for (int i = 0; i < primFields; ++i) {
  1703.         if (fields[i].getField() == null)
  1704.             continue;
  1705.  
  1706.         try {
  1707.             int lower;
  1708.             int upper;
  1709.             int loffset = fields[i].getOffset();
  1710.             
  1711.             switch (fields[i].getTypeCode()) {
  1712.             case 'B':
  1713.             byte byteValue = data[loffset];
  1714.             fields[i].getField().setByte(o, byteValue);
  1715.             break;
  1716.             case 'Z':
  1717.             boolean booleanValue =
  1718.                 (boolean)(data[loffset] != 0);
  1719.             fields[i].getField().setBoolean(o, booleanValue);
  1720.             break;
  1721.             case 'C':
  1722.             char charValue =
  1723.                 (char)(((data[loffset] & 0xff) << 8) +
  1724.                    ((data[loffset+1] & 0xff)));
  1725.             fields[i].getField().setChar(o, charValue);
  1726.             break;
  1727.             case 'S': 
  1728.             short shortValue =
  1729.                 (short)(((data[loffset] & 0xff) << 8) +
  1730.                     ((data[loffset+1] & 0xff)));
  1731.             fields[i].getField().setShort(o, shortValue);
  1732.             break;
  1733.             case 'I':
  1734.             int intValue =
  1735.                 (((data[loffset]   & 0xff) << 24) +
  1736.                  ((data[loffset+1] & 0xff) << 16) +
  1737.                  ((data[loffset+2] & 0xff) << 8) +
  1738.                  ((data[loffset+3] & 0xff)));
  1739.             fields[i].getField().setInt(o, intValue);
  1740.             break;
  1741.             case 'J':
  1742.             upper = (((data[loffset]   & 0xff) << 24) +
  1743.                  ((data[loffset+1] & 0xff) << 16) +
  1744.                  ((data[loffset+2] & 0xff) << 8) +
  1745.                  ((data[loffset+3] & 0xff)));
  1746.             lower = (((data[loffset+4] & 0xff) << 24) +
  1747.                  ((data[loffset+5] & 0xff) << 16) +
  1748.                  ((data[loffset+6] & 0xff) << 8) +
  1749.                  ((data[loffset+7] & 0xff)));
  1750.             long longValue =
  1751.                 ((long)upper << 32) + ((long) lower & 0xFFFFFFFFL);
  1752.             fields[i].getField().setLong(o, longValue);
  1753.             break;
  1754.             case 'F' :
  1755.             int v = (((data[loffset]   & 0xff) << 24) +
  1756.                  ((data[loffset+1] & 0xff) << 16) +
  1757.                  ((data[loffset+2] & 0xff) << 8) +
  1758.                  ((data[loffset+3] & 0xff)));
  1759.             float floatValue = Float.intBitsToFloat(v);
  1760.             fields[i].getField().setFloat(o, floatValue);
  1761.             break;
  1762.             case 'D' :
  1763.             upper = (((data[loffset] & 0xff) << 24) +
  1764.                  ((data[loffset+1] & 0xff) << 16) +
  1765.                  ((data[loffset+2] & 0xff) << 8) +
  1766.                  ((data[loffset+3] & 0xff)));
  1767.             lower = (((data[loffset+4] & 0xff) << 24) +
  1768.                  ((data[loffset+5] & 0xff) << 16) +
  1769.                  ((data[loffset+6] & 0xff) << 8) +
  1770.                  ((data[loffset+7] & 0xff)));
  1771.             long vv =
  1772.                 ((long) upper << 32) + ((long)lower & 0xFFFFFFFFL);
  1773.             double doubleValue = Double.longBitsToDouble(vv);
  1774.             fields[i].getField().setDouble(o, doubleValue);
  1775.             break;
  1776.             default:
  1777.             // "Impossible"
  1778.             throw new InvalidClassException(cl.getName());
  1779.             }
  1780.         } catch (IllegalAccessException e) {
  1781.             throw new InvalidClassException(cl.getName(),
  1782.                             "IllegalAccessException");
  1783.         } catch (IllegalArgumentException e) {
  1784.             /* This case should never happen. If the field types
  1785.                are not the same, InvalidClassException is raised when
  1786.                matching the local class to the serialized ObjectStreamClass. */
  1787.             throw new ClassCastException("Assigning instance of class " +
  1788.                          fields[i].getType().getName() +
  1789.                          " to field " +
  1790.                          currentClassDesc.getName() + '#' +
  1791.                          fields[i].getField().getName());
  1792.         }
  1793.         }
  1794.     }
  1795.  
  1796.     /* Read and set object fields from the input stream. */
  1797.     if (currentClassDesc.objFields > 0) {
  1798.         for (int i = primFields; i < fields.length; i++) {
  1799.         boolean requireLocalClass = (fields[i].getField() != null);
  1800.         Object objectValue = readObject(requireLocalClass);
  1801.         if ((o == null) || (fields[i].getField() == null)) {
  1802.             continue;
  1803.         }
  1804.         try {
  1805.             fields[i].getField().set(o, objectValue);
  1806.         } catch (IllegalAccessException e) {
  1807.             throw new InvalidClassException(cl.getName(),
  1808.                             "IllegalAccessException");
  1809.         } catch (IllegalArgumentException e) {
  1810.             throw new ClassCastException("Assigning instance of class " +
  1811.                          objectValue.getClass().getName() +
  1812.                          " to field " +
  1813.                          currentClassDesc.getName() +
  1814.                          '#' +
  1815.                          fields[i].getField().getName());
  1816.         }
  1817.         }
  1818.     }
  1819.     }
  1820.  
  1821.     /*************************************************************/
  1822.  
  1823.     /**
  1824.      * Provide access to the persistent fields read from the input stream.
  1825.      */
  1826.     abstract public static class GetField {
  1827.  
  1828.      /**
  1829.       * Get the ObjectStreamClass that describes the fields in the stream.
  1830.       */
  1831.      abstract public ObjectStreamClass getObjectStreamClass();
  1832.  
  1833.      /**
  1834.       * Return true if the named field is defaulted and has no value
  1835.       * in this stream.
  1836.       */
  1837.      abstract public boolean defaulted(String name)
  1838.          throws IOException, IllegalArgumentException;
  1839.  
  1840.     /**
  1841.      * Get the value of the named boolean field from the persistent field.
  1842.      */
  1843.     abstract public boolean get(String name, boolean defvalue) 
  1844.         throws IOException, IllegalArgumentException;
  1845.  
  1846.     /**
  1847.      * Get the value of the named char field from the persistent fields.
  1848.      */
  1849.     abstract public char get(String name, char defvalue) 
  1850.         throws IOException, IllegalArgumentException;
  1851.  
  1852.     /**
  1853.      * Get the value of the named byte field from the persistent fields.
  1854.      */
  1855.     abstract public byte get(String name, byte defvalue) 
  1856.         throws IOException, IllegalArgumentException;
  1857.  
  1858.     /**
  1859.      * Get the value of the named short field from the persistent fields.
  1860.      */
  1861.     abstract public short get(String name, short defvalue) 
  1862.         throws IOException, IllegalArgumentException;
  1863.  
  1864.     /**
  1865.      * Get the value of the named int field from the persistent fields.
  1866.      */
  1867.     abstract public int get(String name, int defvalue) 
  1868.         throws IOException, IllegalArgumentException;
  1869.  
  1870.     /**
  1871.      * Get the value of the named long field from the persistent fields.
  1872.      */
  1873.     abstract public long get(String name, long defvalue)
  1874.         throws IOException, IllegalArgumentException;
  1875.  
  1876.     /**
  1877.      * Get the value of the named float field from the persistent fields.
  1878.      */
  1879.     abstract public float get(String name, float defvalue) 
  1880.         throws IOException, IllegalArgumentException;
  1881.  
  1882.     /**
  1883.      * Get the value of the named double field from the persistent field.
  1884.      */
  1885.     abstract public double get(String name, double defvalue) 
  1886.         throws IOException, IllegalArgumentException;
  1887.  
  1888.     /**
  1889.      * Get the value of the named Object field from the persistent field.
  1890.      */
  1891.     abstract public Object get(String name, Object defvalue) 
  1892.         throws IOException, IllegalArgumentException;
  1893.     }
  1894.  
  1895.     /* Internal Implementation of GetField. */
  1896.     static class GetFieldImpl extends GetField {
  1897.  
  1898.         /**
  1899.          * Get the ObjectStreamClass that describes the fields in the stream.
  1900.          */
  1901.         public ObjectStreamClass getObjectStreamClass() {
  1902.         return desc;
  1903.         }
  1904.  
  1905.         /**
  1906.          * Return true if the named field is defaulted and has no value
  1907.          * in this stream.
  1908.          */
  1909.         public boolean defaulted(String name)
  1910.         throws IOException, IllegalArgumentException
  1911.         {
  1912.             ObjectStreamField field = checkField(name, null);
  1913.             return (field == null);       
  1914.         }
  1915.  
  1916.         /**
  1917.          * Get the value of the named boolean field from the persistent field.
  1918.          */
  1919.         public boolean get(String name, boolean defvalue) 
  1920.         throws IOException, IllegalArgumentException
  1921.         {
  1922.             ObjectStreamField field = checkField(name, Boolean.TYPE);
  1923.             if (field == null)
  1924.             return defvalue;
  1925.  
  1926.             return (boolean)(data[field.getOffset()] != 0);
  1927.         }
  1928.  
  1929.         /**
  1930.          * Get the value of the named char field from the persistent fields.
  1931.          */
  1932.         public char get(String name, char defvalue) 
  1933.         throws IOException, IllegalArgumentException
  1934.         {
  1935.             ObjectStreamField field = checkField(name, Character.TYPE);
  1936.             if (field == null)
  1937.             return defvalue;
  1938.  
  1939.             int loffset = field.getOffset();
  1940.             return (char)(((data[loffset] & 0xff) << 8) +
  1941.                   ((data[loffset+1] & 0xff)));
  1942.         }
  1943.  
  1944.         /**
  1945.          * Get the value of the named byte field from the persistent fields.
  1946.          */
  1947.         public byte get(String name, byte defvalue) 
  1948.         throws IOException, IllegalArgumentException
  1949.         {
  1950.             ObjectStreamField field = checkField(name, Byte.TYPE);
  1951.             if (field == null)
  1952.             return defvalue;
  1953.  
  1954.             return data[field.getOffset()];
  1955.         }
  1956.  
  1957.         /**
  1958.          * Get the value of the named short field from the persistent fields.
  1959.          */
  1960.         public short get(String name, short defvalue) 
  1961.         throws IOException, IllegalArgumentException
  1962.         {
  1963.             ObjectStreamField field = checkField(name, Short.TYPE);
  1964.             if (field == null)
  1965.             return defvalue;
  1966.  
  1967.             int loffset = field.getOffset();
  1968.             return (short)(((data[loffset] & 0xff) << 8) +
  1969.                    ((data[loffset+1] & 0xff)));
  1970.         }
  1971.  
  1972.         /**
  1973.          * Get the value of the named int field from the persistent fields.
  1974.          */
  1975.         public int get(String name, int defvalue) 
  1976.         throws IOException, IllegalArgumentException
  1977.         {
  1978.             ObjectStreamField field = checkField(name, Integer.TYPE);
  1979.             if (field == null)
  1980.             return defvalue;
  1981.  
  1982.             int loffset = field.getOffset();         
  1983.             return (((data[loffset] & 0xff) << 24) +
  1984.                 ((data[loffset+1] & 0xff) << 16) +
  1985.                 ((data[loffset+2] & 0xff) << 8) +
  1986.                 ((data[loffset+3] & 0xff)));
  1987.         }
  1988.  
  1989.         /**
  1990.          * Get the value of the named long field from the persistent fields.
  1991.          */
  1992.         public long get(String name, long defvalue) 
  1993.         throws IOException, IllegalArgumentException
  1994.         {
  1995.             ObjectStreamField field = checkField(name, Long.TYPE);
  1996.             if (field == null)
  1997.             return defvalue;
  1998.  
  1999.             int loffset = field.getOffset();         
  2000.             int upper = (((data[loffset] & 0xff) << 24) +
  2001.                  ((data[loffset+1] & 0xff) << 16) +
  2002.                  ((data[loffset+2] & 0xff) << 8) +
  2003.                  ((data[loffset+3] & 0xff)));
  2004.             int lower = (((data[loffset+4] & 0xff) << 24) +
  2005.                  ((data[loffset+5] & 0xff) << 16) +
  2006.                  ((data[loffset+6] & 0xff) << 8) +
  2007.                  ((data[loffset+7] & 0xff)));
  2008.             long v = ((long)upper << 32) + ((long)lower & 0xFFFFFFFFL);
  2009.             return v;
  2010.         }
  2011.  
  2012.         /**
  2013.          * Get the value of the named float field from the persistent fields.
  2014.          */
  2015.         public float get(String name, float defvalue) 
  2016.         throws IOException, IllegalArgumentException
  2017.         {
  2018.             ObjectStreamField field = checkField(name, Float.TYPE);
  2019.             if (field == null)
  2020.             return defvalue;
  2021.  
  2022.             int loffset = field.getOffset();         
  2023.             int v = (((data[loffset] & 0xff) << 24) +
  2024.                  ((data[loffset+1] & 0xff) << 16) +
  2025.                  ((data[loffset+2] & 0xff) << 8) +
  2026.                  ((data[loffset+3] & 0xff)));
  2027.             return Float.intBitsToFloat(v);
  2028.         }
  2029.  
  2030.         /**
  2031.          * Get the value of the named double field from the persistent field.
  2032.          */
  2033.         public double get(String name, double defvalue) 
  2034.         throws IOException, IllegalArgumentException
  2035.         {
  2036.             ObjectStreamField field = checkField(name, Double.TYPE);
  2037.             if (field == null)
  2038.             return defvalue;
  2039.  
  2040.             int loffset = field.getOffset();         
  2041.             int upper = (((data[loffset] & 0xff) << 24) +
  2042.                  ((data[loffset+1] & 0xff) << 16) +
  2043.                  ((data[loffset+2] & 0xff) << 8) +
  2044.                  ((data[loffset+3] & 0xff)));
  2045.             int lower = (((data[loffset+4] & 0xff) << 24) +
  2046.                  ((data[loffset+5] & 0xff) << 16) +
  2047.                  ((data[loffset+6] & 0xff) << 8) +
  2048.                  ((data[loffset+7] & 0xff)));
  2049.             long v = ((long)upper << 32) + ((long)lower & 0xFFFFFFFFL);
  2050.             return Double.longBitsToDouble(v);
  2051.         }
  2052.  
  2053.         /**
  2054.          * Get the value of the named Object field from the persistent field.
  2055.          */
  2056.         public Object get(String name, Object defvalue) 
  2057.         throws IOException, IllegalArgumentException
  2058.         {
  2059.             ObjectStreamField field = checkField(name, Object.class);
  2060.             if (field == null)
  2061.             return defvalue;
  2062.  
  2063.             return objects[field.getOffset()];
  2064.  
  2065.         }
  2066.  
  2067.         /*
  2068.          * Retrieve the named field.
  2069.          * If the field is known in the current descriptor return it.
  2070.          * If not, find the descriptor for the class that is being
  2071.          * read into and check the name.  If the name is not
  2072.          * valid in the class throw a IllegalArgumentException.
  2073.          * otherwise return null.
  2074.          */
  2075.         private ObjectStreamField checkField(String name, Class type)
  2076.         throws IllegalArgumentException
  2077.         {
  2078.             ObjectStreamField field = desc.getField(name);
  2079.             if (field != null) {
  2080.             /*
  2081.              * Check the type of the field in the stream.
  2082.              * If correct return the field.
  2083.              */
  2084.             if (type != null && type != field.getType())
  2085.                 throw new IllegalArgumentException("field type incorrect");
  2086.             return field;
  2087.             } else {
  2088.             /* Check the name in the local classes descriptor.
  2089.              * If found it's a valid persistent field an
  2090.              * should be defaulted.
  2091.              * If not the caller shouldn't be using that name.
  2092.              */
  2093.             ObjectStreamClass localdesc =
  2094.                 ObjectStreamClass.lookup(desc.forClass());
  2095.             if (localdesc == null)
  2096.                 throw new IllegalArgumentException("No local class descriptor");
  2097.  
  2098.             ObjectStreamField localfield = localdesc.getField(name);
  2099.             if (localfield == null)
  2100.                 throw new IllegalArgumentException("no such field");
  2101.             if (type != null && type != localfield.getType() &&
  2102.                 (type.isPrimitive() || localfield.getType().isPrimitive()))
  2103.                 throw new IllegalArgumentException("field type incorrect");
  2104.             return null;
  2105.             }
  2106.         }
  2107.  
  2108.         /**
  2109.          * Read the data and fields from the specified stream.
  2110.          */
  2111.         void read(ObjectInputStream in)
  2112.         throws IOException, ClassNotFoundException
  2113.         {
  2114.             if (data != null)
  2115.             in.readFully(data, 0, data.length);
  2116.  
  2117.             if (objects != null) {
  2118.             for (int i = 0; i < objects.length; i++) {
  2119.                 /* don't require local class when reading object from stream.*/
  2120.                 objects[i] = in.readObject(false);
  2121.             }
  2122.             }
  2123.         }
  2124.  
  2125.         /**
  2126.          * Create a GetField object for the a Class.
  2127.          * Allocate the arrays for primitives and objects.
  2128.          */
  2129.         GetFieldImpl(ObjectStreamClass descriptor){
  2130.         desc = descriptor;
  2131.         if (desc.primBytes > 0)
  2132.             data = new byte[desc.primBytes];
  2133.         if (desc.objFields > 0)
  2134.             objects = new Object[desc.objFields];
  2135.         }
  2136.  
  2137.         /*
  2138.          * The byte array that contains the bytes for the primitive fields.
  2139.          * The Object array that contains the objects for the object fields.
  2140.          */
  2141.         private byte[] data;
  2142.         private Object[] objects;
  2143.         private ObjectStreamClass desc;
  2144.     }
  2145.  
  2146.     /* Remember the first exception that stopped this stream. */
  2147.     private IOException abortIOException = null;
  2148.     private ClassNotFoundException abortClassNotFoundException = null;
  2149.  
  2150.     /* Allocate a new object for the specified class
  2151.      * Native since newInstance may not be able to find a zero arg constructor.
  2152.      */
  2153.     private static native Object allocateNewObject(Class aclass, Class initclass)
  2154.     throws InstantiationException, IllegalAccessException;
  2155.     
  2156.     /* Allocate a new array for the specified class
  2157.      * Native since the type of the array needs to be set to the class
  2158.      */
  2159.     private static native Object allocateNewArray(Class aclass, int length);
  2160.     
  2161.     /* The object is the current object and class is the the current
  2162.      * subclass of the object being read. Nesting information is kept
  2163.      * on the stack.
  2164.      */
  2165.     private Object currentObject;
  2166.     private ObjectStreamClass currentClassDesc;
  2167.     private Class currentClass;
  2168.     private Object currentGetFields;
  2169.  
  2170.     /*
  2171.      * Primitive data are read from the input stream and stored in
  2172.      * this array. The array is allocated prior to first use.
  2173.      */
  2174.     private static final int INITIAL_BUFFER_SIZE = 512;
  2175.     private byte[] data;
  2176.  
  2177.     /* Arrays used to keep track of classes and ObjectStreamClasses
  2178.      * as they are being merged; used in inputObject.
  2179.      * spClass is the stack pointer for both.  */
  2180.     ObjectStreamClass[] classdesc;
  2181.     Class[] classes;
  2182.     int spClass;
  2183.  
  2184.     /* During deserialization the objects in the stream are represented by
  2185.      * handles (ints), they need to be mapped to the objects.
  2186.      * The vector is indexed by the offset between baseWireHandle and the
  2187.      * wire handle in the stream.
  2188.      */
  2189.     private Vector wireHandle2Object;
  2190.     private int nextWireOffset;
  2191.  
  2192.     /* Vector of validation callback objects
  2193.      * The vector is created as needed, and ValidationCallback objects added
  2194.      * for each call to registerObject. The vector is maintained in
  2195.      * order of highest (first) priority to lowest
  2196.      */
  2197.     private Vector callbacks;
  2198.  
  2199.     /* Recursion level, starts at zero and is incremented for each entry
  2200.      * to readObject.  Decremented before exit.
  2201.      */ 
  2202.     private int recursionDepth;
  2203.  
  2204.     /* Last code Peek'ed, if any */
  2205.     private byte currCode;
  2206.  
  2207.     /* 
  2208.      * Flag set to true to allow resolveObject to be called.
  2209.      * Set by enableResolveObject.
  2210.      */
  2211.     boolean enableResolve;
  2212.  
  2213.  
  2214.     /* if true, override readObject implementation with readObjectOverride.
  2215.      */
  2216.     private boolean enableSubclassImplementation;
  2217. };
  2218.  
  2219. // Internal class to hold the Callback object and priority
  2220. class ValidationCallback {
  2221.     ValidationCallback(ObjectInputValidation cb, int prio) {
  2222.     callback = cb;
  2223.     priority = prio;
  2224.     }
  2225.  
  2226.     int priority;            // priority of this callback
  2227.     ObjectInputValidation callback; // object to be called back
  2228. }
  2229.