Save This Page
Home » openjdk-7 » java » io » [javadoc | source]
    1   /*
    2    * Copyright 1996-2006 Sun Microsystems, Inc.  All Rights Reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   
   26   package java.io;
   27   
   28   import java.io.ObjectStreamClass.WeakClassKey;
   29   import java.lang.ref.ReferenceQueue;
   30   import java.lang.reflect.Array;
   31   import java.lang.reflect.Modifier;
   32   import java.lang.reflect.Proxy;
   33   import java.security.AccessControlContext;
   34   import java.security.AccessController;
   35   import java.security.PrivilegedAction;
   36   import java.security.PrivilegedActionException;
   37   import java.security.PrivilegedExceptionAction;
   38   import java.util.Arrays;
   39   import java.util.HashMap;
   40   import java.util.concurrent.ConcurrentHashMap;
   41   import java.util.concurrent.ConcurrentMap;
   42   import java.util.concurrent.atomic.AtomicBoolean;
   43   import static java.io.ObjectStreamClass.processQueue;
   44   
   45   /**
   46    * An ObjectInputStream deserializes primitive data and objects previously
   47    * written using an ObjectOutputStream.
   48    *
   49    * <p>ObjectOutputStream and ObjectInputStream can provide an application with
   50    * persistent storage for graphs of objects when used with a FileOutputStream
   51    * and FileInputStream respectively.  ObjectInputStream is used to recover
   52    * those objects previously serialized. Other uses include passing objects
   53    * between hosts using a socket stream or for marshaling and unmarshaling
   54    * arguments and parameters in a remote communication system.
   55    *
   56    * <p>ObjectInputStream ensures that the types of all objects in the graph
   57    * created from the stream match the classes present in the Java Virtual
   58    * Machine.  Classes are loaded as required using the standard mechanisms.
   59    *
   60    * <p>Only objects that support the java.io.Serializable or
   61    * java.io.Externalizable interface can be read from streams.
   62    *
   63    * <p>The method <code>readObject</code> is used to read an object from the
   64    * stream.  Java's safe casting should be used to get the desired type.  In
   65    * Java, strings and arrays are objects and are treated as objects during
   66    * serialization. When read they need to be cast to the expected type.
   67    *
   68    * <p>Primitive data types can be read from the stream using the appropriate
   69    * method on DataInput.
   70    *
   71    * <p>The default deserialization mechanism for objects restores the contents
   72    * of each field to the value and type it had when it was written.  Fields
   73    * declared as transient or static are ignored by the deserialization process.
   74    * References to other objects cause those objects to be read from the stream
   75    * as necessary.  Graphs of objects are restored correctly using a reference
   76    * sharing mechanism.  New objects are always allocated when deserializing,
   77    * which prevents existing objects from being overwritten.
   78    *
   79    * <p>Reading an object is analogous to running the constructors of a new
   80    * object.  Memory is allocated for the object and initialized to zero (NULL).
   81    * No-arg constructors are invoked for the non-serializable classes and then
   82    * the fields of the serializable classes are restored from the stream starting
   83    * with the serializable class closest to java.lang.object and finishing with
   84    * the object's most specific class.
   85    *
   86    * <p>For example to read from a stream as written by the example in
   87    * ObjectOutputStream:
   88    * <br>
   89    * <pre>
   90    *      FileInputStream fis = new FileInputStream("t.tmp");
   91    *      ObjectInputStream ois = new ObjectInputStream(fis);
   92    *
   93    *      int i = ois.readInt();
   94    *      String today = (String) ois.readObject();
   95    *      Date date = (Date) ois.readObject();
   96    *
   97    *      ois.close();
   98    * </pre>
   99    *
  100    * <p>Classes control how they are serialized by implementing either the
  101    * java.io.Serializable or java.io.Externalizable interfaces.
  102    *
  103    * <p>Implementing the Serializable interface allows object serialization to
  104    * save and restore the entire state of the object and it allows classes to
  105    * evolve between the time the stream is written and the time it is read.  It
  106    * automatically traverses references between objects, saving and restoring
  107    * entire graphs.
  108    *
  109    * <p>Serializable classes that require special handling during the
  110    * serialization and deserialization process should implement the following
  111    * methods:<p>
  112    *
  113    * <pre>
  114    * private void writeObject(java.io.ObjectOutputStream stream)
  115    *     throws IOException;
  116    * private void readObject(java.io.ObjectInputStream stream)
  117    *     throws IOException, ClassNotFoundException;
  118    * private void readObjectNoData()
  119    *     throws ObjectStreamException;
  120    * </pre>
  121    *
  122    * <p>The readObject method is responsible for reading and restoring the state
  123    * of the object for its particular class using data written to the stream by
  124    * the corresponding writeObject method.  The method does not need to concern
  125    * itself with the state belonging to its superclasses or subclasses.  State is
  126    * restored by reading data from the ObjectInputStream for the individual
  127    * fields and making assignments to the appropriate fields of the object.
  128    * Reading primitive data types is supported by DataInput.
  129    *
  130    * <p>Any attempt to read object data which exceeds the boundaries of the
  131    * custom data written by the corresponding writeObject method will cause an
  132    * OptionalDataException to be thrown with an eof field value of true.
  133    * Non-object reads which exceed the end of the allotted data will reflect the
  134    * end of data in the same way that they would indicate the end of the stream:
  135    * bytewise reads will return -1 as the byte read or number of bytes read, and
  136    * primitive reads will throw EOFExceptions.  If there is no corresponding
  137    * writeObject method, then the end of default serialized data marks the end of
  138    * the allotted data.
  139    *
  140    * <p>Primitive and object read calls issued from within a readExternal method
  141    * behave in the same manner--if the stream is already positioned at the end of
  142    * data written by the corresponding writeExternal method, object reads will
  143    * throw OptionalDataExceptions with eof set to true, bytewise reads will
  144    * return -1, and primitive reads will throw EOFExceptions.  Note that this
  145    * behavior does not hold for streams written with the old
  146    * <code>ObjectStreamConstants.PROTOCOL_VERSION_1</code> protocol, in which the
  147    * end of data written by writeExternal methods is not demarcated, and hence
  148    * cannot be detected.
  149    *
  150    * <p>The readObjectNoData method is responsible for initializing the state of
  151    * the object for its particular class in the event that the serialization
  152    * stream does not list the given class as a superclass of the object being
  153    * deserialized.  This may occur in cases where the receiving party uses a
  154    * different version of the deserialized instance's class than the sending
  155    * party, and the receiver's version extends classes that are not extended by
  156    * the sender's version.  This may also occur if the serialization stream has
  157    * been tampered; hence, readObjectNoData is useful for initializing
  158    * deserialized objects properly despite a "hostile" or incomplete source
  159    * stream.
  160    *
  161    * <p>Serialization does not read or assign values to the fields of any object
  162    * that does not implement the java.io.Serializable interface.  Subclasses of
  163    * Objects that are not serializable can be serializable. In this case the
  164    * non-serializable class must have a no-arg constructor to allow its fields to
  165    * be initialized.  In this case it is the responsibility of the subclass to
  166    * save and restore the state of the non-serializable class. It is frequently
  167    * the case that the fields of that class are accessible (public, package, or
  168    * protected) or that there are get and set methods that can be used to restore
  169    * the state.
  170    *
  171    * <p>Any exception that occurs while deserializing an object will be caught by
  172    * the ObjectInputStream and abort the reading process.
  173    *
  174    * <p>Implementing the Externalizable interface allows the object to assume
  175    * complete control over the contents and format of the object's serialized
  176    * form.  The methods of the Externalizable interface, writeExternal and
  177    * readExternal, are called to save and restore the objects state.  When
  178    * implemented by a class they can write and read their own state using all of
  179    * the methods of ObjectOutput and ObjectInput.  It is the responsibility of
  180    * the objects to handle any versioning that occurs.
  181    *
  182    * <p>Enum constants are deserialized differently than ordinary serializable or
  183    * externalizable objects.  The serialized form of an enum constant consists
  184    * solely of its name; field values of the constant are not transmitted.  To
  185    * deserialize an enum constant, ObjectInputStream reads the constant name from
  186    * the stream; the deserialized constant is then obtained by calling the static
  187    * method <code>Enum.valueOf(Class, String)</code> with the enum constant's
  188    * base type and the received constant name as arguments.  Like other
  189    * serializable or externalizable objects, enum constants can function as the
  190    * targets of back references appearing subsequently in the serialization
  191    * stream.  The process by which enum constants are deserialized cannot be
  192    * customized: any class-specific readObject, readObjectNoData, and readResolve
  193    * methods defined by enum types are ignored during deserialization.
  194    * Similarly, any serialPersistentFields or serialVersionUID field declarations
  195    * are also ignored--all enum types have a fixed serialVersionUID of 0L.
  196    *
  197    * @author      Mike Warres
  198    * @author      Roger Riggs
  199    * @see java.io.DataInput
  200    * @see java.io.ObjectOutputStream
  201    * @see java.io.Serializable
  202    * @see <a href="../../../platform/serialization/spec/input.html"> Object Serialization Specification, Section 3, Object Input Classes</a>
  203    * @since   JDK1.1
  204    */
  205   public class ObjectInputStream
  206       extends InputStream implements ObjectInput, ObjectStreamConstants
  207   {
  208       /** handle value representing null */
  209       private static final int NULL_HANDLE = -1;
  210   
  211       /** marker for unshared objects in internal handle table */
  212       private static final Object unsharedMarker = new Object();
  213   
  214       /** table mapping primitive type names to corresponding class objects */
  215       private static final HashMap<String, Class<?>> primClasses
  216           = new HashMap<String, Class<?>>(8, 1.0F);
  217       static {
  218           primClasses.put("boolean", boolean.class);
  219           primClasses.put("byte", byte.class);
  220           primClasses.put("char", char.class);
  221           primClasses.put("short", short.class);
  222           primClasses.put("int", int.class);
  223           primClasses.put("long", long.class);
  224           primClasses.put("float", float.class);
  225           primClasses.put("double", double.class);
  226           primClasses.put("void", void.class);
  227       }
  228   
  229       private static class Caches {
  230           /** cache of subclass security audit results */
  231           static final ConcurrentMap<WeakClassKey,Boolean> subclassAudits =
  232               new ConcurrentHashMap<WeakClassKey,Boolean>();
  233   
  234           /** queue for WeakReferences to audited subclasses */
  235           static final ReferenceQueue<Class<?>> subclassAuditsQueue =
  236               new ReferenceQueue<Class<?>>();
  237       }
  238   
  239       /** filter stream for handling block data conversion */
  240       private final BlockDataInputStream bin;
  241       /** validation callback list */
  242       private final ValidationList vlist;
  243       /** recursion depth */
  244       private int depth;
  245       /** whether stream is closed */
  246       private boolean closed;
  247   
  248       /** wire handle -> obj/exception map */
  249       private final HandleTable handles;
  250       /** scratch field for passing handle values up/down call stack */
  251       private int passHandle = NULL_HANDLE;
  252       /** flag set when at end of field value block with no TC_ENDBLOCKDATA */
  253       private boolean defaultDataEnd = false;
  254   
  255       /** buffer for reading primitive field values */
  256       private byte[] primVals;
  257   
  258       /** if true, invoke readObjectOverride() instead of readObject() */
  259       private final boolean enableOverride;
  260       /** if true, invoke resolveObject() */
  261       private boolean enableResolve;
  262   
  263       /**
  264        * Context during upcalls to class-defined readObject methods; holds
  265        * object currently being deserialized and descriptor for current class.
  266        * Null when not during readObject upcall.
  267        */
  268       private CallbackContext curContext;
  269   
  270       /**
  271        * Creates an ObjectInputStream that reads from the specified InputStream.
  272        * A serialization stream header is read from the stream and verified.
  273        * This constructor will block until the corresponding ObjectOutputStream
  274        * has written and flushed the header.
  275        *
  276        * <p>If a security manager is installed, this constructor will check for
  277        * the "enableSubclassImplementation" SerializablePermission when invoked
  278        * directly or indirectly by the constructor of a subclass which overrides
  279        * the ObjectInputStream.readFields or ObjectInputStream.readUnshared
  280        * methods.
  281        *
  282        * @param   in input stream to read from
  283        * @throws  StreamCorruptedException if the stream header is incorrect
  284        * @throws  IOException if an I/O error occurs while reading stream header
  285        * @throws  SecurityException if untrusted subclass illegally overrides
  286        *          security-sensitive methods
  287        * @throws  NullPointerException if <code>in</code> is <code>null</code>
  288        * @see     ObjectInputStream#ObjectInputStream()
  289        * @see     ObjectInputStream#readFields()
  290        * @see     ObjectOutputStream#ObjectOutputStream(OutputStream)
  291        */
  292       public ObjectInputStream(InputStream in) throws IOException {
  293           verifySubclass();
  294           bin = new BlockDataInputStream(in);
  295           handles = new HandleTable(10);
  296           vlist = new ValidationList();
  297           enableOverride = false;
  298           readStreamHeader();
  299           bin.setBlockDataMode(true);
  300       }
  301   
  302       /**
  303        * Provide a way for subclasses that are completely reimplementing
  304        * ObjectInputStream to not have to allocate private data just used by this
  305        * implementation of ObjectInputStream.
  306        *
  307        * <p>If there is a security manager installed, this method first calls the
  308        * security manager's <code>checkPermission</code> method with the
  309        * <code>SerializablePermission("enableSubclassImplementation")</code>
  310        * permission to ensure it's ok to enable subclassing.
  311        *
  312        * @throws  SecurityException if a security manager exists and its
  313        *          <code>checkPermission</code> method denies enabling
  314        *          subclassing.
  315        * @see SecurityManager#checkPermission
  316        * @see java.io.SerializablePermission
  317        */
  318       protected ObjectInputStream() throws IOException, SecurityException {
  319           SecurityManager sm = System.getSecurityManager();
  320           if (sm != null) {
  321               sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
  322           }
  323           bin = null;
  324           handles = null;
  325           vlist = null;
  326           enableOverride = true;
  327       }
  328   
  329       /**
  330        * Read an object from the ObjectInputStream.  The class of the object, the
  331        * signature of the class, and the values of the non-transient and
  332        * non-static fields of the class and all of its supertypes are read.
  333        * Default deserializing for a class can be overriden using the writeObject
  334        * and readObject methods.  Objects referenced by this object are read
  335        * transitively so that a complete equivalent graph of objects is
  336        * reconstructed by readObject.
  337        *
  338        * <p>The root object is completely restored when all of its fields and the
  339        * objects it references are completely restored.  At this point the object
  340        * validation callbacks are executed in order based on their registered
  341        * priorities. The callbacks are registered by objects (in the readObject
  342        * special methods) as they are individually restored.
  343        *
  344        * <p>Exceptions are thrown for problems with the InputStream and for
  345        * classes that should not be deserialized.  All exceptions are fatal to
  346        * the InputStream and leave it in an indeterminate state; it is up to the
  347        * caller to ignore or recover the stream state.
  348        *
  349        * @throws  ClassNotFoundException Class of a serialized object cannot be
  350        *          found.
  351        * @throws  InvalidClassException Something is wrong with a class used by
  352        *          serialization.
  353        * @throws  StreamCorruptedException Control information in the
  354        *          stream is inconsistent.
  355        * @throws  OptionalDataException Primitive data was found in the
  356        *          stream instead of objects.
  357        * @throws  IOException Any of the usual Input/Output related exceptions.
  358        */
  359       public final Object readObject()
  360           throws IOException, ClassNotFoundException
  361       {
  362           if (enableOverride) {
  363               return readObjectOverride();
  364           }
  365   
  366           // if nested read, passHandle contains handle of enclosing object
  367           int outerHandle = passHandle;
  368           try {
  369               Object obj = readObject0(false);
  370               handles.markDependency(outerHandle, passHandle);
  371               ClassNotFoundException ex = handles.lookupException(passHandle);
  372               if (ex != null) {
  373                   throw ex;
  374               }
  375               if (depth == 0) {
  376                   vlist.doCallbacks();
  377               }
  378               return obj;
  379           } finally {
  380               passHandle = outerHandle;
  381               if (closed && depth == 0) {
  382                   clear();
  383               }
  384           }
  385       }
  386   
  387       /**
  388        * This method is called by trusted subclasses of ObjectOutputStream that
  389        * constructed ObjectOutputStream using the protected no-arg constructor.
  390        * The subclass is expected to provide an override method with the modifier
  391        * "final".
  392        *
  393        * @return  the Object read from the stream.
  394        * @throws  ClassNotFoundException Class definition of a serialized object
  395        *          cannot be found.
  396        * @throws  OptionalDataException Primitive data was found in the stream
  397        *          instead of objects.
  398        * @throws  IOException if I/O errors occurred while reading from the
  399        *          underlying stream
  400        * @see #ObjectInputStream()
  401        * @see #readObject()
  402        * @since 1.2
  403        */
  404       protected Object readObjectOverride()
  405           throws IOException, ClassNotFoundException
  406       {
  407           return null;
  408       }
  409   
  410       /**
  411        * Reads an "unshared" object from the ObjectInputStream.  This method is
  412        * identical to readObject, except that it prevents subsequent calls to
  413        * readObject and readUnshared from returning additional references to the
  414        * deserialized instance obtained via this call.  Specifically:
  415        * <ul>
  416        *   <li>If readUnshared is called to deserialize a back-reference (the
  417        *       stream representation of an object which has been written
  418        *       previously to the stream), an ObjectStreamException will be
  419        *       thrown.
  420        *
  421        *   <li>If readUnshared returns successfully, then any subsequent attempts
  422        *       to deserialize back-references to the stream handle deserialized
  423        *       by readUnshared will cause an ObjectStreamException to be thrown.
  424        * </ul>
  425        * Deserializing an object via readUnshared invalidates the stream handle
  426        * associated with the returned object.  Note that this in itself does not
  427        * always guarantee that the reference returned by readUnshared is unique;
  428        * the deserialized object may define a readResolve method which returns an
  429        * object visible to other parties, or readUnshared may return a Class
  430        * object or enum constant obtainable elsewhere in the stream or through
  431        * external means. If the deserialized object defines a readResolve method
  432        * and the invocation of that method returns an array, then readUnshared
  433        * returns a shallow clone of that array; this guarantees that the returned
  434        * array object is unique and cannot be obtained a second time from an
  435        * invocation of readObject or readUnshared on the ObjectInputStream,
  436        * even if the underlying data stream has been manipulated.
  437        *
  438        * <p>ObjectInputStream subclasses which override this method can only be
  439        * constructed in security contexts possessing the
  440        * "enableSubclassImplementation" SerializablePermission; any attempt to
  441        * instantiate such a subclass without this permission will cause a
  442        * SecurityException to be thrown.
  443        *
  444        * @return  reference to deserialized object
  445        * @throws  ClassNotFoundException if class of an object to deserialize
  446        *          cannot be found
  447        * @throws  StreamCorruptedException if control information in the stream
  448        *          is inconsistent
  449        * @throws  ObjectStreamException if object to deserialize has already
  450        *          appeared in stream
  451        * @throws  OptionalDataException if primitive data is next in stream
  452        * @throws  IOException if an I/O error occurs during deserialization
  453        * @since   1.4
  454        */
  455       public Object readUnshared() throws IOException, ClassNotFoundException {
  456           // if nested read, passHandle contains handle of enclosing object
  457           int outerHandle = passHandle;
  458           try {
  459               Object obj = readObject0(true);
  460               handles.markDependency(outerHandle, passHandle);
  461               ClassNotFoundException ex = handles.lookupException(passHandle);
  462               if (ex != null) {
  463                   throw ex;
  464               }
  465               if (depth == 0) {
  466                   vlist.doCallbacks();
  467               }
  468               return obj;
  469           } finally {
  470               passHandle = outerHandle;
  471               if (closed && depth == 0) {
  472                   clear();
  473               }
  474           }
  475       }
  476   
  477       /**
  478        * Read the non-static and non-transient fields of the current class from
  479        * this stream.  This may only be called from the readObject method of the
  480        * class being deserialized. It will throw the NotActiveException if it is
  481        * called otherwise.
  482        *
  483        * @throws  ClassNotFoundException if the class of a serialized object
  484        *          could not be found.
  485        * @throws  IOException if an I/O error occurs.
  486        * @throws  NotActiveException if the stream is not currently reading
  487        *          objects.
  488        */
  489       public void defaultReadObject()
  490           throws IOException, ClassNotFoundException
  491       {
  492           if (curContext == null) {
  493               throw new NotActiveException("not in call to readObject");
  494           }
  495           Object curObj = curContext.getObj();
  496           ObjectStreamClass curDesc = curContext.getDesc();
  497           bin.setBlockDataMode(false);
  498           defaultReadFields(curObj, curDesc);
  499           bin.setBlockDataMode(true);
  500           if (!curDesc.hasWriteObjectData()) {
  501               /*
  502                * Fix for 4360508: since stream does not contain terminating
  503                * TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere
  504                * knows to simulate end-of-custom-data behavior.
  505                */
  506               defaultDataEnd = true;
  507           }
  508           ClassNotFoundException ex = handles.lookupException(passHandle);
  509           if (ex != null) {
  510               throw ex;
  511           }
  512       }
  513   
  514       /**
  515        * Reads the persistent fields from the stream and makes them available by
  516        * name.
  517        *
  518        * @return  the <code>GetField</code> object representing the persistent
  519        *          fields of the object being deserialized
  520        * @throws  ClassNotFoundException if the class of a serialized object
  521        *          could not be found.
  522        * @throws  IOException if an I/O error occurs.
  523        * @throws  NotActiveException if the stream is not currently reading
  524        *          objects.
  525        * @since 1.2
  526        */
  527       public ObjectInputStream.GetField readFields()
  528           throws IOException, ClassNotFoundException
  529       {
  530           if (curContext == null) {
  531               throw new NotActiveException("not in call to readObject");
  532           }
  533           Object curObj = curContext.getObj();
  534           ObjectStreamClass curDesc = curContext.getDesc();
  535           bin.setBlockDataMode(false);
  536           GetFieldImpl getField = new GetFieldImpl(curDesc);
  537           getField.readFields();
  538           bin.setBlockDataMode(true);
  539           if (!curDesc.hasWriteObjectData()) {
  540               /*
  541                * Fix for 4360508: since stream does not contain terminating
  542                * TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere
  543                * knows to simulate end-of-custom-data behavior.
  544                */
  545               defaultDataEnd = true;
  546           }
  547   
  548           return getField;
  549       }
  550   
  551       /**
  552        * Register an object to be validated before the graph is returned.  While
  553        * similar to resolveObject these validations are called after the entire
  554        * graph has been reconstituted.  Typically, a readObject method will
  555        * register the object with the stream so that when all of the objects are
  556        * restored a final set of validations can be performed.
  557        *
  558        * @param   obj the object to receive the validation callback.
  559        * @param   prio controls the order of callbacks;zero is a good default.
  560        *          Use higher numbers to be called back earlier, lower numbers for
  561        *          later callbacks. Within a priority, callbacks are processed in
  562        *          no particular order.
  563        * @throws  NotActiveException The stream is not currently reading objects
  564        *          so it is invalid to register a callback.
  565        * @throws  InvalidObjectException The validation object is null.
  566        */
  567       public void registerValidation(ObjectInputValidation obj, int prio)
  568           throws NotActiveException, InvalidObjectException
  569       {
  570           if (depth == 0) {
  571               throw new NotActiveException("stream inactive");
  572           }
  573           vlist.register(obj, prio);
  574       }
  575   
  576       /**
  577        * Load the local class equivalent of the specified stream class
  578        * description.  Subclasses may implement this method to allow classes to
  579        * be fetched from an alternate source.
  580        *
  581        * <p>The corresponding method in <code>ObjectOutputStream</code> is
  582        * <code>annotateClass</code>.  This method will be invoked only once for
  583        * each unique class in the stream.  This method can be implemented by
  584        * subclasses to use an alternate loading mechanism but must return a
  585        * <code>Class</code> object. Once returned, if the class is not an array
  586        * class, its serialVersionUID is compared to the serialVersionUID of the
  587        * serialized class, and if there is a mismatch, the deserialization fails
  588        * and an {@link InvalidClassException} is thrown.
  589        *
  590        * <p>The default implementation of this method in
  591        * <code>ObjectInputStream</code> returns the result of calling
  592        * <pre>
  593        *     Class.forName(desc.getName(), false, loader)
  594        * </pre>
  595        * where <code>loader</code> is determined as follows: if there is a
  596        * method on the current thread's stack whose declaring class was
  597        * defined by a user-defined class loader (and was not a generated to
  598        * implement reflective invocations), then <code>loader</code> is class
  599        * loader corresponding to the closest such method to the currently
  600        * executing frame; otherwise, <code>loader</code> is
  601        * <code>null</code>. If this call results in a
  602        * <code>ClassNotFoundException</code> and the name of the passed
  603        * <code>ObjectStreamClass</code> instance is the Java language keyword
  604        * for a primitive type or void, then the <code>Class</code> object
  605        * representing that primitive type or void will be returned
  606        * (e.g., an <code>ObjectStreamClass</code> with the name
  607        * <code>"int"</code> will be resolved to <code>Integer.TYPE</code>).
  608        * Otherwise, the <code>ClassNotFoundException</code> will be thrown to
  609        * the caller of this method.
  610        *
  611        * @param   desc an instance of class <code>ObjectStreamClass</code>
  612        * @return  a <code>Class</code> object corresponding to <code>desc</code>
  613        * @throws  IOException any of the usual Input/Output exceptions.
  614        * @throws  ClassNotFoundException if class of a serialized object cannot
  615        *          be found.
  616        */
  617       protected Class<?> resolveClass(ObjectStreamClass desc)
  618           throws IOException, ClassNotFoundException
  619       {
  620           String name = desc.getName();
  621           try {
  622               return Class.forName(name, false, latestUserDefinedLoader());
  623           } catch (ClassNotFoundException ex) {
  624               Class<?> cl = primClasses.get(name);
  625               if (cl != null) {
  626                   return cl;
  627               } else {
  628                   throw ex;
  629               }
  630           }
  631       }
  632   
  633       /**
  634        * Returns a proxy class that implements the interfaces named in a proxy
  635        * class descriptor; subclasses may implement this method to read custom
  636        * data from the stream along with the descriptors for dynamic proxy
  637        * classes, allowing them to use an alternate loading mechanism for the
  638        * interfaces and the proxy class.
  639        *
  640        * <p>This method is called exactly once for each unique proxy class
  641        * descriptor in the stream.
  642        *
  643        * <p>The corresponding method in <code>ObjectOutputStream</code> is
  644        * <code>annotateProxyClass</code>.  For a given subclass of
  645        * <code>ObjectInputStream</code> that overrides this method, the
  646        * <code>annotateProxyClass</code> method in the corresponding subclass of
  647        * <code>ObjectOutputStream</code> must write any data or objects read by
  648        * this method.
  649        *
  650        * <p>The default implementation of this method in
  651        * <code>ObjectInputStream</code> returns the result of calling
  652        * <code>Proxy.getProxyClass</code> with the list of <code>Class</code>
  653        * objects for the interfaces that are named in the <code>interfaces</code>
  654        * parameter.  The <code>Class</code> object for each interface name
  655        * <code>i</code> is the value returned by calling
  656        * <pre>
  657        *     Class.forName(i, false, loader)
  658        * </pre>
  659        * where <code>loader</code> is that of the first non-<code>null</code>
  660        * class loader up the execution stack, or <code>null</code> if no
  661        * non-<code>null</code> class loaders are on the stack (the same class
  662        * loader choice used by the <code>resolveClass</code> method).  Unless any
  663        * of the resolved interfaces are non-public, this same value of
  664        * <code>loader</code> is also the class loader passed to
  665        * <code>Proxy.getProxyClass</code>; if non-public interfaces are present,
  666        * their class loader is passed instead (if more than one non-public
  667        * interface class loader is encountered, an
  668        * <code>IllegalAccessError</code> is thrown).
  669        * If <code>Proxy.getProxyClass</code> throws an
  670        * <code>IllegalArgumentException</code>, <code>resolveProxyClass</code>
  671        * will throw a <code>ClassNotFoundException</code> containing the
  672        * <code>IllegalArgumentException</code>.
  673        *
  674        * @param interfaces the list of interface names that were
  675        *                deserialized in the proxy class descriptor
  676        * @return  a proxy class for the specified interfaces
  677        * @throws        IOException any exception thrown by the underlying
  678        *                <code>InputStream</code>
  679        * @throws        ClassNotFoundException if the proxy class or any of the
  680        *                named interfaces could not be found
  681        * @see ObjectOutputStream#annotateProxyClass(Class)
  682        * @since 1.3
  683        */
  684       protected Class<?> resolveProxyClass(String[] interfaces)
  685           throws IOException, ClassNotFoundException
  686       {
  687           ClassLoader latestLoader = latestUserDefinedLoader();
  688           ClassLoader nonPublicLoader = null;
  689           boolean hasNonPublicInterface = false;
  690   
  691           // define proxy in class loader of non-public interface(s), if any
  692           Class[] classObjs = new Class[interfaces.length];
  693           for (int i = 0; i < interfaces.length; i++) {
  694               Class cl = Class.forName(interfaces[i], false, latestLoader);
  695               if ((cl.getModifiers() & Modifier.PUBLIC) == 0) {
  696                   if (hasNonPublicInterface) {
  697                       if (nonPublicLoader != cl.getClassLoader()) {
  698                           throw new IllegalAccessError(
  699                               "conflicting non-public interface class loaders");
  700                       }
  701                   } else {
  702                       nonPublicLoader = cl.getClassLoader();
  703                       hasNonPublicInterface = true;
  704                   }
  705               }
  706               classObjs[i] = cl;
  707           }
  708           try {
  709               return Proxy.getProxyClass(
  710                   hasNonPublicInterface ? nonPublicLoader : latestLoader,
  711                   classObjs);
  712           } catch (IllegalArgumentException e) {
  713               throw new ClassNotFoundException(null, e);
  714           }
  715       }
  716   
  717       /**
  718        * This method will allow trusted subclasses of ObjectInputStream to
  719        * substitute one object for another during deserialization. Replacing
  720        * objects is disabled until enableResolveObject is called. The
  721        * enableResolveObject method checks that the stream requesting to resolve
  722        * object can be trusted. Every reference to serializable objects is passed
  723        * to resolveObject.  To insure that the private state of objects is not
  724        * unintentionally exposed only trusted streams may use resolveObject.
  725        *
  726        * <p>This method is called after an object has been read but before it is
  727        * returned from readObject.  The default resolveObject method just returns
  728        * the same object.
  729        *
  730        * <p>When a subclass is replacing objects it must insure that the
  731        * substituted object is compatible with every field where the reference
  732        * will be stored.  Objects whose type is not a subclass of the type of the
  733        * field or array element abort the serialization by raising an exception
  734        * and the object is not be stored.
  735        *
  736        * <p>This method is called only once when each object is first
  737        * encountered.  All subsequent references to the object will be redirected
  738        * to the new object.
  739        *
  740        * @param   obj object to be substituted
  741        * @return  the substituted object
  742        * @throws  IOException Any of the usual Input/Output exceptions.
  743        */
  744       protected Object resolveObject(Object obj) throws IOException {
  745           return obj;
  746       }
  747   
  748       /**
  749        * Enable the stream to allow objects read from the stream to be replaced.
  750        * When enabled, the resolveObject method is called for every object being
  751        * deserialized.
  752        *
  753        * <p>If <i>enable</i> is true, and there is a security manager installed,
  754        * this method first calls the security manager's
  755        * <code>checkPermission</code> method with the
  756        * <code>SerializablePermission("enableSubstitution")</code> permission to
  757        * ensure it's ok to enable the stream to allow objects read from the
  758        * stream to be replaced.
  759        *
  760        * @param   enable true for enabling use of <code>resolveObject</code> for
  761        *          every object being deserialized
  762        * @return  the previous setting before this method was invoked
  763        * @throws  SecurityException if a security manager exists and its
  764        *          <code>checkPermission</code> method denies enabling the stream
  765        *          to allow objects read from the stream to be replaced.
  766        * @see SecurityManager#checkPermission
  767        * @see java.io.SerializablePermission
  768        */
  769       protected boolean enableResolveObject(boolean enable)
  770           throws SecurityException
  771       {
  772           if (enable == enableResolve) {
  773               return enable;
  774           }
  775           if (enable) {
  776               SecurityManager sm = System.getSecurityManager();
  777               if (sm != null) {
  778                   sm.checkPermission(SUBSTITUTION_PERMISSION);
  779               }
  780           }
  781           enableResolve = enable;
  782           return !enableResolve;
  783       }
  784   
  785       /**
  786        * The readStreamHeader method is provided to allow subclasses to read and
  787        * verify their own stream headers. It reads and verifies the magic number
  788        * and version number.
  789        *
  790        * @throws  IOException if there are I/O errors while reading from the
  791        *          underlying <code>InputStream</code>
  792        * @throws  StreamCorruptedException if control information in the stream
  793        *          is inconsistent
  794        */
  795       protected void readStreamHeader()
  796           throws IOException, StreamCorruptedException
  797       {
  798           short s0 = bin.readShort();
  799           short s1 = bin.readShort();
  800           if (s0 != STREAM_MAGIC || s1 != STREAM_VERSION) {
  801               throw new StreamCorruptedException(
  802                   String.format("invalid stream header: %04X%04X", s0, s1));
  803           }
  804       }
  805   
  806       /**
  807        * Read a class descriptor from the serialization stream.  This method is
  808        * called when the ObjectInputStream expects a class descriptor as the next
  809        * item in the serialization stream.  Subclasses of ObjectInputStream may
  810        * override this method to read in class descriptors that have been written
  811        * in non-standard formats (by subclasses of ObjectOutputStream which have
  812        * overridden the <code>writeClassDescriptor</code> method).  By default,
  813        * this method reads class descriptors according to the format defined in
  814        * the Object Serialization specification.
  815        *
  816        * @return  the class descriptor read
  817        * @throws  IOException If an I/O error has occurred.
  818        * @throws  ClassNotFoundException If the Class of a serialized object used
  819        *          in the class descriptor representation cannot be found
  820        * @see java.io.ObjectOutputStream#writeClassDescriptor(java.io.ObjectStreamClass)
  821        * @since 1.3
  822        */
  823       protected ObjectStreamClass readClassDescriptor()
  824           throws IOException, ClassNotFoundException
  825       {
  826           ObjectStreamClass desc = new ObjectStreamClass();
  827           desc.readNonProxy(this);
  828           return desc;
  829       }
  830   
  831       /**
  832        * Reads a byte of data. This method will block if no input is available.
  833        *
  834        * @return  the byte read, or -1 if the end of the stream is reached.
  835        * @throws  IOException If an I/O error has occurred.
  836        */
  837       public int read() throws IOException {
  838           return bin.read();
  839       }
  840   
  841       /**
  842        * Reads into an array of bytes.  This method will block until some input
  843        * is available. Consider using java.io.DataInputStream.readFully to read
  844        * exactly 'length' bytes.
  845        *
  846        * @param   buf the buffer into which the data is read
  847        * @param   off the start offset of the data
  848        * @param   len the maximum number of bytes read
  849        * @return  the actual number of bytes read, -1 is returned when the end of
  850        *          the stream is reached.
  851        * @throws  IOException If an I/O error has occurred.
  852        * @see java.io.DataInputStream#readFully(byte[],int,int)
  853        */
  854       public int read(byte[] buf, int off, int len) throws IOException {
  855           if (buf == null) {
  856               throw new NullPointerException();
  857           }
  858           int endoff = off + len;
  859           if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) {
  860               throw new IndexOutOfBoundsException();
  861           }
  862           return bin.read(buf, off, len, false);
  863       }
  864   
  865       /**
  866        * Returns the number of bytes that can be read without blocking.
  867        *
  868        * @return  the number of available bytes.
  869        * @throws  IOException if there are I/O errors while reading from the
  870        *          underlying <code>InputStream</code>
  871        */
  872       public int available() throws IOException {
  873           return bin.available();
  874       }
  875   
  876       /**
  877        * Closes the input stream. Must be called to release any resources
  878        * associated with the stream.
  879        *
  880        * @throws  IOException If an I/O error has occurred.
  881        */
  882       public void close() throws IOException {
  883           /*
  884            * Even if stream already closed, propagate redundant close to
  885            * underlying stream to stay consistent with previous implementations.
  886            */
  887           closed = true;
  888           if (depth == 0) {
  889               clear();
  890           }
  891           bin.close();
  892       }
  893   
  894       /**
  895        * Reads in a boolean.
  896        *
  897        * @return  the boolean read.
  898        * @throws  EOFException If end of file is reached.
  899        * @throws  IOException If other I/O error has occurred.
  900        */
  901       public boolean readBoolean() throws IOException {
  902           return bin.readBoolean();
  903       }
  904   
  905       /**
  906        * Reads an 8 bit byte.
  907        *
  908        * @return  the 8 bit byte read.
  909        * @throws  EOFException If end of file is reached.
  910        * @throws  IOException If other I/O error has occurred.
  911        */
  912       public byte readByte() throws IOException  {
  913           return bin.readByte();
  914       }
  915   
  916       /**
  917        * Reads an unsigned 8 bit byte.
  918        *
  919        * @return  the 8 bit byte read.
  920        * @throws  EOFException If end of file is reached.
  921        * @throws  IOException If other I/O error has occurred.
  922        */
  923       public int readUnsignedByte()  throws IOException {
  924           return bin.readUnsignedByte();
  925       }
  926   
  927       /**
  928        * Reads a 16 bit char.
  929        *
  930        * @return  the 16 bit char read.
  931        * @throws  EOFException If end of file is reached.
  932        * @throws  IOException If other I/O error has occurred.
  933        */
  934       public char readChar()  throws IOException {
  935           return bin.readChar();
  936       }
  937   
  938       /**
  939        * Reads a 16 bit short.
  940        *
  941        * @return  the 16 bit short read.
  942        * @throws  EOFException If end of file is reached.
  943        * @throws  IOException If other I/O error has occurred.
  944        */
  945       public short readShort()  throws IOException {
  946           return bin.readShort();
  947       }
  948   
  949       /**
  950        * Reads an unsigned 16 bit short.
  951        *
  952        * @return  the 16 bit short read.
  953        * @throws  EOFException If end of file is reached.
  954        * @throws  IOException If other I/O error has occurred.
  955        */
  956       public int readUnsignedShort() throws IOException {
  957           return bin.readUnsignedShort();
  958       }
  959   
  960       /**
  961        * Reads a 32 bit int.
  962        *
  963        * @return  the 32 bit integer read.
  964        * @throws  EOFException If end of file is reached.
  965        * @throws  IOException If other I/O error has occurred.
  966        */
  967       public int readInt()  throws IOException {
  968           return bin.readInt();
  969       }
  970   
  971       /**
  972        * Reads a 64 bit long.
  973        *
  974        * @return  the read 64 bit long.
  975        * @throws  EOFException If end of file is reached.
  976        * @throws  IOException If other I/O error has occurred.
  977        */
  978       public long readLong()  throws IOException {
  979           return bin.readLong();
  980       }
  981   
  982       /**
  983        * Reads a 32 bit float.
  984        *
  985        * @return  the 32 bit float read.
  986        * @throws  EOFException If end of file is reached.
  987        * @throws  IOException If other I/O error has occurred.
  988        */
  989       public float readFloat() throws IOException {
  990           return bin.readFloat();
  991       }
  992   
  993       /**
  994        * Reads a 64 bit double.
  995        *
  996        * @return  the 64 bit double read.
  997        * @throws  EOFException If end of file is reached.
  998        * @throws  IOException If other I/O error has occurred.
  999        */
 1000       public double readDouble() throws IOException {
 1001           return bin.readDouble();
 1002       }
 1003   
 1004       /**
 1005        * Reads bytes, blocking until all bytes are read.
 1006        *
 1007        * @param   buf the buffer into which the data is read
 1008        * @throws  EOFException If end of file is reached.
 1009        * @throws  IOException If other I/O error has occurred.
 1010        */
 1011       public void readFully(byte[] buf) throws IOException {
 1012           bin.readFully(buf, 0, buf.length, false);
 1013       }
 1014   
 1015       /**
 1016        * Reads bytes, blocking until all bytes are read.
 1017        *
 1018        * @param   buf the buffer into which the data is read
 1019        * @param   off the start offset of the data
 1020        * @param   len the maximum number of bytes to read
 1021        * @throws  EOFException If end of file is reached.
 1022        * @throws  IOException If other I/O error has occurred.
 1023        */
 1024       public void readFully(byte[] buf, int off, int len) throws IOException {
 1025           int endoff = off + len;
 1026           if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) {
 1027               throw new IndexOutOfBoundsException();
 1028           }
 1029           bin.readFully(buf, off, len, false);
 1030       }
 1031   
 1032       /**
 1033        * Skips bytes.
 1034        *
 1035        * @param   len the number of bytes to be skipped
 1036        * @return  the actual number of bytes skipped.
 1037        * @throws  IOException If an I/O error has occurred.
 1038        */
 1039       public int skipBytes(int len) throws IOException {
 1040           return bin.skipBytes(len);
 1041       }
 1042   
 1043       /**
 1044        * Reads in a line that has been terminated by a \n, \r, \r\n or EOF.
 1045        *
 1046        * @return  a String copy of the line.
 1047        * @throws  IOException if there are I/O errors while reading from the
 1048        *          underlying <code>InputStream</code>
 1049        * @deprecated This method does not properly convert bytes to characters.
 1050        *          see DataInputStream for the details and alternatives.
 1051        */
 1052       @Deprecated
 1053       public String readLine() throws IOException {
 1054           return bin.readLine();
 1055       }
 1056   
 1057       /**
 1058        * Reads a String in
 1059        * <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
 1060        * format.
 1061        *
 1062        * @return  the String.
 1063        * @throws  IOException if there are I/O errors while reading from the
 1064        *          underlying <code>InputStream</code>
 1065        * @throws  UTFDataFormatException if read bytes do not represent a valid
 1066        *          modified UTF-8 encoding of a string
 1067        */
 1068       public String readUTF() throws IOException {
 1069           return bin.readUTF();
 1070       }
 1071   
 1072       /**
 1073        * Provide access to the persistent fields read from the input stream.
 1074        */
 1075       public static abstract class GetField {
 1076   
 1077           /**
 1078            * Get the ObjectStreamClass that describes the fields in the stream.
 1079            *
 1080            * @return  the descriptor class that describes the serializable fields
 1081            */
 1082           public abstract ObjectStreamClass getObjectStreamClass();
 1083   
 1084           /**
 1085            * Return true if the named field is defaulted and has no value in this
 1086            * stream.
 1087            *
 1088            * @param  name the name of the field
 1089            * @return true, if and only if the named field is defaulted
 1090            * @throws IOException if there are I/O errors while reading from
 1091            *         the underlying <code>InputStream</code>
 1092            * @throws IllegalArgumentException if <code>name</code> does not
 1093            *         correspond to a serializable field
 1094            */
 1095           public abstract boolean defaulted(String name) throws IOException;
 1096   
 1097           /**
 1098            * Get the value of the named boolean field from the persistent field.
 1099            *
 1100            * @param  name the name of the field
 1101            * @param  val the default value to use if <code>name</code> does not
 1102            *         have a value
 1103            * @return the value of the named <code>boolean</code> field
 1104            * @throws IOException if there are I/O errors while reading from the
 1105            *         underlying <code>InputStream</code>
 1106            * @throws IllegalArgumentException if type of <code>name</code> is
 1107            *         not serializable or if the field type is incorrect
 1108            */
 1109           public abstract boolean get(String name, boolean val)
 1110               throws IOException;
 1111   
 1112           /**
 1113            * Get the value of the named byte field from the persistent field.
 1114            *
 1115            * @param  name the name of the field
 1116            * @param  val the default value to use if <code>name</code> does not
 1117            *         have a value
 1118            * @return the value of the named <code>byte</code> field
 1119            * @throws IOException if there are I/O errors while reading from the
 1120            *         underlying <code>InputStream</code>
 1121            * @throws IllegalArgumentException if type of <code>name</code> is
 1122            *         not serializable or if the field type is incorrect
 1123            */
 1124           public abstract byte get(String name, byte val) throws IOException;
 1125   
 1126           /**
 1127            * Get the value of the named char field from the persistent field.
 1128            *
 1129            * @param  name the name of the field
 1130            * @param  val the default value to use if <code>name</code> does not
 1131            *         have a value
 1132            * @return the value of the named <code>char</code> field
 1133            * @throws IOException if there are I/O errors while reading from the
 1134            *         underlying <code>InputStream</code>
 1135            * @throws IllegalArgumentException if type of <code>name</code> is
 1136            *         not serializable or if the field type is incorrect
 1137            */
 1138           public abstract char get(String name, char val) throws IOException;
 1139   
 1140           /**
 1141            * Get the value of the named short field from the persistent field.
 1142            *
 1143            * @param  name the name of the field
 1144            * @param  val the default value to use if <code>name</code> does not
 1145            *         have a value
 1146            * @return the value of the named <code>short</code> field
 1147            * @throws IOException if there are I/O errors while reading from the
 1148            *         underlying <code>InputStream</code>
 1149            * @throws IllegalArgumentException if type of <code>name</code> is
 1150            *         not serializable or if the field type is incorrect
 1151            */
 1152           public abstract short get(String name, short val) throws IOException;
 1153   
 1154           /**
 1155            * Get the value of the named int field from the persistent field.
 1156            *
 1157            * @param  name the name of the field
 1158            * @param  val the default value to use if <code>name</code> does not
 1159            *         have a value
 1160            * @return the value of the named <code>int</code> field
 1161            * @throws IOException if there are I/O errors while reading from the
 1162            *         underlying <code>InputStream</code>
 1163            * @throws IllegalArgumentException if type of <code>name</code> is
 1164            *         not serializable or if the field type is incorrect
 1165            */
 1166           public abstract int get(String name, int val) throws IOException;
 1167   
 1168           /**
 1169            * Get the value of the named long field from the persistent field.
 1170            *
 1171            * @param  name the name of the field
 1172            * @param  val the default value to use if <code>name</code> does not
 1173            *         have a value
 1174            * @return the value of the named <code>long</code> field
 1175            * @throws IOException if there are I/O errors while reading from the
 1176            *         underlying <code>InputStream</code>
 1177            * @throws IllegalArgumentException if type of <code>name</code> is
 1178            *         not serializable or if the field type is incorrect
 1179            */
 1180           public abstract long get(String name, long val) throws IOException;
 1181   
 1182           /**
 1183            * Get the value of the named float field from the persistent field.
 1184            *
 1185            * @param  name the name of the field
 1186            * @param  val the default value to use if <code>name</code> does not
 1187            *         have a value
 1188            * @return the value of the named <code>float</code> field
 1189            * @throws IOException if there are I/O errors while reading from the
 1190            *         underlying <code>InputStream</code>
 1191            * @throws IllegalArgumentException if type of <code>name</code> is
 1192            *         not serializable or if the field type is incorrect
 1193            */
 1194           public abstract float get(String name, float val) throws IOException;
 1195   
 1196           /**
 1197            * Get the value of the named double field from the persistent field.
 1198            *
 1199            * @param  name the name of the field
 1200            * @param  val the default value to use if <code>name</code> does not
 1201            *         have a value
 1202            * @return the value of the named <code>double</code> field
 1203            * @throws IOException if there are I/O errors while reading from the
 1204            *         underlying <code>InputStream</code>
 1205            * @throws IllegalArgumentException if type of <code>name</code> is
 1206            *         not serializable or if the field type is incorrect
 1207            */
 1208           public abstract double get(String name, double val) throws IOException;
 1209   
 1210           /**
 1211            * Get the value of the named Object field from the persistent field.
 1212            *
 1213            * @param  name the name of the field
 1214            * @param  val the default value to use if <code>name</code> does not
 1215            *         have a value
 1216            * @return the value of the named <code>Object</code> field
 1217            * @throws IOException if there are I/O errors while reading from the
 1218            *         underlying <code>InputStream</code>
 1219            * @throws IllegalArgumentException if type of <code>name</code> is
 1220            *         not serializable or if the field type is incorrect
 1221            */
 1222           public abstract Object get(String name, Object val) throws IOException;
 1223       }
 1224   
 1225       /**
 1226        * Verifies that this (possibly subclass) instance can be constructed
 1227        * without violating security constraints: the subclass must not override
 1228        * security-sensitive non-final methods, or else the
 1229        * "enableSubclassImplementation" SerializablePermission is checked.
 1230        */
 1231       private void verifySubclass() {
 1232           Class cl = getClass();
 1233           if (cl == ObjectInputStream.class) {
 1234               return;
 1235           }
 1236           SecurityManager sm = System.getSecurityManager();
 1237           if (sm == null) {
 1238               return;
 1239           }
 1240           processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits);
 1241           WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue);
 1242           Boolean result = Caches.subclassAudits.get(key);
 1243           if (result == null) {
 1244               result = Boolean.valueOf(auditSubclass(cl));
 1245               Caches.subclassAudits.putIfAbsent(key, result);
 1246           }
 1247           if (result.booleanValue()) {
 1248               return;
 1249           }
 1250           sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
 1251       }
 1252   
 1253       /**
 1254        * Performs reflective checks on given subclass to verify that it doesn't
 1255        * override security-sensitive non-final methods.  Returns true if subclass
 1256        * is "safe", false otherwise.
 1257        */
 1258       private static boolean auditSubclass(final Class<?> subcl) {
 1259           Boolean result = AccessController.doPrivileged(
 1260               new PrivilegedAction<Boolean>() {
 1261                   public Boolean run() {
 1262                       for (Class<?> cl = subcl;
 1263                            cl != ObjectInputStream.class;
 1264                            cl = cl.getSuperclass())
 1265                       {
 1266                           try {
 1267                               cl.getDeclaredMethod(
 1268                                   "readUnshared", (Class[]) null);
 1269                               return Boolean.FALSE;
 1270                           } catch (NoSuchMethodException ex) {
 1271                           }
 1272                           try {
 1273                               cl.getDeclaredMethod("readFields", (Class[]) null);
 1274                               return Boolean.FALSE;
 1275                           } catch (NoSuchMethodException ex) {
 1276                           }
 1277                       }
 1278                       return Boolean.TRUE;
 1279                   }
 1280               }
 1281           );
 1282           return result.booleanValue();
 1283       }
 1284   
 1285       /**
 1286        * Clears internal data structures.
 1287        */
 1288       private void clear() {
 1289           handles.clear();
 1290           vlist.clear();
 1291       }
 1292   
 1293       /**
 1294        * Underlying readObject implementation.
 1295        */
 1296       private Object readObject0(boolean unshared) throws IOException {
 1297           boolean oldMode = bin.getBlockDataMode();
 1298           if (oldMode) {
 1299               int remain = bin.currentBlockRemaining();
 1300               if (remain > 0) {
 1301                   throw new OptionalDataException(remain);
 1302               } else if (defaultDataEnd) {
 1303                   /*
 1304                    * Fix for 4360508: stream is currently at the end of a field
 1305                    * value block written via default serialization; since there
 1306                    * is no terminating TC_ENDBLOCKDATA tag, simulate
 1307                    * end-of-custom-data behavior explicitly.
 1308                    */
 1309                   throw new OptionalDataException(true);
 1310               }
 1311               bin.setBlockDataMode(false);
 1312           }
 1313   
 1314           byte tc;
 1315           while ((tc = bin.peekByte()) == TC_RESET) {
 1316               bin.readByte();
 1317               handleReset();
 1318           }
 1319   
 1320           depth++;
 1321           try {
 1322               switch (tc) {
 1323                   case TC_NULL:
 1324                       return readNull();
 1325   
 1326                   case TC_REFERENCE:
 1327                       return readHandle(unshared);
 1328   
 1329                   case TC_CLASS:
 1330                       return readClass(unshared);
 1331   
 1332                   case TC_CLASSDESC:
 1333                   case TC_PROXYCLASSDESC:
 1334                       return readClassDesc(unshared);
 1335   
 1336                   case TC_STRING:
 1337                   case TC_LONGSTRING:
 1338                       return checkResolve(readString(unshared));
 1339   
 1340                   case TC_ARRAY:
 1341                       return checkResolve(readArray(unshared));
 1342   
 1343                   case TC_ENUM:
 1344                       return checkResolve(readEnum(unshared));
 1345   
 1346                   case TC_OBJECT:
 1347                       return checkResolve(readOrdinaryObject(unshared));
 1348   
 1349                   case TC_EXCEPTION:
 1350                       IOException ex = readFatalException();
 1351                       throw new WriteAbortedException("writing aborted", ex);
 1352   
 1353                   case TC_BLOCKDATA:
 1354                   case TC_BLOCKDATALONG:
 1355                       if (oldMode) {
 1356                           bin.setBlockDataMode(true);
 1357                           bin.peek();             // force header read
 1358                           throw new OptionalDataException(
 1359                               bin.currentBlockRemaining());
 1360                       } else {
 1361                           throw new StreamCorruptedException(
 1362                               "unexpected block data");
 1363                       }
 1364   
 1365                   case TC_ENDBLOCKDATA:
 1366                       if (oldMode) {
 1367                           throw new OptionalDataException(true);
 1368                       } else {
 1369                           throw new StreamCorruptedException(
 1370                               "unexpected end of block data");
 1371                       }
 1372   
 1373                   default:
 1374                       throw new StreamCorruptedException(
 1375                           String.format("invalid type code: %02X", tc));
 1376               }
 1377           } finally {
 1378               depth--;
 1379               bin.setBlockDataMode(oldMode);
 1380           }
 1381       }
 1382   
 1383       /**
 1384        * If resolveObject has been enabled and given object does not have an
 1385        * exception associated with it, calls resolveObject to determine
 1386        * replacement for object, and updates handle table accordingly.  Returns
 1387        * replacement object, or echoes provided object if no replacement
 1388        * occurred.  Expects that passHandle is set to given object's handle prior
 1389        * to calling this method.
 1390        */
 1391       private Object checkResolve(Object obj) throws IOException {
 1392           if (!enableResolve || handles.lookupException(passHandle) != null) {
 1393               return obj;
 1394           }
 1395           Object rep = resolveObject(obj);
 1396           if (rep != obj) {
 1397               handles.setObject(passHandle, rep);
 1398           }
 1399           return rep;
 1400       }
 1401   
 1402       /**
 1403        * Reads string without allowing it to be replaced in stream.  Called from
 1404        * within ObjectStreamClass.read().
 1405        */
 1406       String readTypeString() throws IOException {
 1407           int oldHandle = passHandle;
 1408           try {
 1409               byte tc = bin.peekByte();
 1410               switch (tc) {
 1411                   case TC_NULL:
 1412                       return (String) readNull();
 1413   
 1414                   case TC_REFERENCE:
 1415                       return (String) readHandle(false);
 1416   
 1417                   case TC_STRING:
 1418                   case TC_LONGSTRING:
 1419                       return readString(false);
 1420   
 1421                   default:
 1422                       throw new StreamCorruptedException(
 1423                           String.format("invalid type code: %02X", tc));
 1424               }
 1425           } finally {
 1426               passHandle = oldHandle;
 1427           }
 1428       }
 1429   
 1430       /**
 1431        * Reads in null code, sets passHandle to NULL_HANDLE and returns null.
 1432        */
 1433       private Object readNull() throws IOException {
 1434           if (bin.readByte() != TC_NULL) {
 1435               throw new InternalError();
 1436           }
 1437           passHandle = NULL_HANDLE;
 1438           return null;
 1439       }
 1440   
 1441       /**
 1442        * Reads in object handle, sets passHandle to the read handle, and returns
 1443        * object associated with the handle.
 1444        */
 1445       private Object readHandle(boolean unshared) throws IOException {
 1446           if (bin.readByte() != TC_REFERENCE) {
 1447               throw new InternalError();
 1448           }
 1449           passHandle = bin.readInt() - baseWireHandle;
 1450           if (passHandle < 0 || passHandle >= handles.size()) {
 1451               throw new StreamCorruptedException(
 1452                   String.format("invalid handle value: %08X", passHandle +
 1453                   baseWireHandle));
 1454           }
 1455           if (unshared) {
 1456               // REMIND: what type of exception to throw here?
 1457               throw new InvalidObjectException(
 1458                   "cannot read back reference as unshared");
 1459           }
 1460   
 1461           Object obj = handles.lookupObject(passHandle);
 1462           if (obj == unsharedMarker) {
 1463               // REMIND: what type of exception to throw here?
 1464               throw new InvalidObjectException(
 1465                   "cannot read back reference to unshared object");
 1466           }
 1467           return obj;
 1468       }
 1469   
 1470       /**
 1471        * Reads in and returns class object.  Sets passHandle to class object's
 1472        * assigned handle.  Returns null if class is unresolvable (in which case a
 1473        * ClassNotFoundException will be associated with the class' handle in the
 1474        * handle table).
 1475        */
 1476       private Class readClass(boolean unshared) throws IOException {
 1477           if (bin.readByte() != TC_CLASS) {
 1478               throw new InternalError();
 1479           }
 1480           ObjectStreamClass desc = readClassDesc(false);
 1481           Class cl = desc.forClass();
 1482           passHandle = handles.assign(unshared ? unsharedMarker : cl);
 1483   
 1484           ClassNotFoundException resolveEx = desc.getResolveException();
 1485           if (resolveEx != null) {
 1486               handles.markException(passHandle, resolveEx);
 1487           }
 1488   
 1489           handles.finish(passHandle);
 1490           return cl;
 1491       }
 1492   
 1493       /**
 1494        * Reads in and returns (possibly null) class descriptor.  Sets passHandle
 1495        * to class descriptor's assigned handle.  If class descriptor cannot be
 1496        * resolved to a class in the local VM, a ClassNotFoundException is
 1497        * associated with the class descriptor's handle.
 1498        */
 1499       private ObjectStreamClass readClassDesc(boolean unshared)
 1500           throws IOException
 1501       {
 1502           byte tc = bin.peekByte();
 1503           switch (tc) {
 1504               case TC_NULL:
 1505                   return (ObjectStreamClass) readNull();
 1506   
 1507               case TC_REFERENCE:
 1508                   return (ObjectStreamClass) readHandle(unshared);
 1509   
 1510               case TC_PROXYCLASSDESC:
 1511                   return readProxyDesc(unshared);
 1512   
 1513               case TC_CLASSDESC:
 1514                   return readNonProxyDesc(unshared);
 1515   
 1516               default:
 1517                   throw new StreamCorruptedException(
 1518                       String.format("invalid type code: %02X", tc));
 1519           }
 1520       }
 1521   
 1522       /**
 1523        * Reads in and returns class descriptor for a dynamic proxy class.  Sets
 1524        * passHandle to proxy class descriptor's assigned handle.  If proxy class
 1525        * descriptor cannot be resolved to a class in the local VM, a
 1526        * ClassNotFoundException is associated with the descriptor's handle.
 1527        */
 1528       private ObjectStreamClass readProxyDesc(boolean unshared)
 1529           throws IOException
 1530       {
 1531           if (bin.readByte() != TC_PROXYCLASSDESC) {
 1532               throw new InternalError();
 1533           }
 1534   
 1535           ObjectStreamClass desc = new ObjectStreamClass();
 1536           int descHandle = handles.assign(unshared ? unsharedMarker : desc);
 1537           passHandle = NULL_HANDLE;
 1538   
 1539           int numIfaces = bin.readInt();
 1540           String[] ifaces = new String[numIfaces];
 1541           for (int i = 0; i < numIfaces; i++) {
 1542               ifaces[i] = bin.readUTF();
 1543           }
 1544   
 1545           Class cl = null;
 1546           ClassNotFoundException resolveEx = null;
 1547           bin.setBlockDataMode(true);
 1548           try {
 1549               if ((cl = resolveProxyClass(ifaces)) == null) {
 1550                   resolveEx = new ClassNotFoundException("null class");
 1551               }
 1552           } catch (ClassNotFoundException ex) {
 1553               resolveEx = ex;
 1554           }
 1555           skipCustomData();
 1556   
 1557           desc.initProxy(cl, resolveEx, readClassDesc(false));
 1558   
 1559           handles.finish(descHandle);
 1560           passHandle = descHandle;
 1561           return desc;
 1562       }
 1563   
 1564       /**
 1565        * Reads in and returns class descriptor for a class that is not a dynamic
 1566        * proxy class.  Sets passHandle to class descriptor's assigned handle.  If
 1567        * class descriptor cannot be resolved to a class in the local VM, a
 1568        * ClassNotFoundException is associated with the descriptor's handle.
 1569        */
 1570       private ObjectStreamClass readNonProxyDesc(boolean unshared)
 1571           throws IOException
 1572       {
 1573           if (bin.readByte() != TC_CLASSDESC) {
 1574               throw new InternalError();
 1575           }
 1576   
 1577           ObjectStreamClass desc = new ObjectStreamClass();
 1578           int descHandle = handles.assign(unshared ? unsharedMarker : desc);
 1579           passHandle = NULL_HANDLE;
 1580   
 1581           ObjectStreamClass readDesc = null;
 1582           try {
 1583               readDesc = readClassDescriptor();
 1584           } catch (ClassNotFoundException ex) {
 1585               throw (IOException) new InvalidClassException(
 1586                   "failed to read class descriptor").initCause(ex);
 1587           }
 1588   
 1589           Class cl = null;
 1590           ClassNotFoundException resolveEx = null;
 1591           bin.setBlockDataMode(true);
 1592           try {
 1593               if ((cl = resolveClass(readDesc)) == null) {
 1594                   resolveEx = new ClassNotFoundException("null class");
 1595               }
 1596           } catch (ClassNotFoundException ex) {
 1597               resolveEx = ex;
 1598           }
 1599           skipCustomData();
 1600   
 1601           desc.initNonProxy(readDesc, cl, resolveEx, readClassDesc(false));
 1602   
 1603           handles.finish(descHandle);
 1604           passHandle = descHandle;
 1605           return desc;
 1606       }
 1607   
 1608       /**
 1609        * Reads in and returns new string.  Sets passHandle to new string's
 1610        * assigned handle.
 1611        */
 1612       private String readString(boolean unshared) throws IOException {
 1613           String str;
 1614           byte tc = bin.readByte();
 1615           switch (tc) {
 1616               case TC_STRING:
 1617                   str = bin.readUTF();
 1618                   break;
 1619   
 1620               case TC_LONGSTRING:
 1621                   str = bin.readLongUTF();
 1622                   break;
 1623   
 1624               default:
 1625                   throw new StreamCorruptedException(
 1626                       String.format("invalid type code: %02X", tc));
 1627           }
 1628           passHandle = handles.assign(unshared ? unsharedMarker : str);
 1629           handles.finish(passHandle);
 1630           return str;
 1631       }
 1632   
 1633       /**
 1634        * Reads in and returns array object, or null if array class is
 1635        * unresolvable.  Sets passHandle to array's assigned handle.
 1636        */
 1637       private Object readArray(boolean unshared) throws IOException {
 1638           if (bin.readByte() != TC_ARRAY) {
 1639               throw new InternalError();
 1640           }
 1641   
 1642           ObjectStreamClass desc = readClassDesc(false);
 1643           int len = bin.readInt();
 1644   
 1645           Object array = null;
 1646           Class cl, ccl = null;
 1647           if ((cl = desc.forClass()) != null) {
 1648               ccl = cl.getComponentType();
 1649               array = Array.newInstance(ccl, len);
 1650           }
 1651   
 1652           int arrayHandle = handles.assign(unshared ? unsharedMarker : array);
 1653           ClassNotFoundException resolveEx = desc.getResolveException();
 1654           if (resolveEx != null) {
 1655               handles.markException(arrayHandle, resolveEx);
 1656           }
 1657   
 1658           if (ccl == null) {
 1659               for (int i = 0; i < len; i++) {
 1660                   readObject0(false);
 1661               }
 1662           } else if (ccl.isPrimitive()) {
 1663               if (ccl == Integer.TYPE) {
 1664                   bin.readInts((int[]) array, 0, len);
 1665               } else if (ccl == Byte.TYPE) {
 1666                   bin.readFully((byte[]) array, 0, len, true);
 1667               } else if (ccl == Long.TYPE) {
 1668                   bin.readLongs((long[]) array, 0, len);
 1669               } else if (ccl == Float.TYPE) {
 1670                   bin.readFloats((float[]) array, 0, len);
 1671               } else if (ccl == Double.TYPE) {
 1672                   bin.readDoubles((double[]) array, 0, len);
 1673               } else if (ccl == Short.TYPE) {
 1674                   bin.readShorts((short[]) array, 0, len);
 1675               } else if (ccl == Character.TYPE) {
 1676                   bin.readChars((char[]) array, 0, len);
 1677               } else if (ccl == Boolean.TYPE) {
 1678                   bin.readBooleans((boolean[]) array, 0, len);
 1679               } else {
 1680                   throw new InternalError();
 1681               }
 1682           } else {
 1683               Object[] oa = (Object[]) array;
 1684               for (int i = 0; i < len; i++) {
 1685                   oa[i] = readObject0(false);
 1686                   handles.markDependency(arrayHandle, passHandle);
 1687               }
 1688           }
 1689   
 1690           handles.finish(arrayHandle);
 1691           passHandle = arrayHandle;
 1692           return array;
 1693       }
 1694   
 1695       /**
 1696        * Reads in and returns enum constant, or null if enum type is
 1697        * unresolvable.  Sets passHandle to enum constant's assigned handle.
 1698        */
 1699       private Enum readEnum(boolean unshared) throws IOException {
 1700           if (bin.readByte() != TC_ENUM) {
 1701               throw new InternalError();
 1702           }
 1703   
 1704           ObjectStreamClass desc = readClassDesc(false);
 1705           if (!desc.isEnum()) {
 1706               throw new InvalidClassException("non-enum class: " + desc);
 1707           }
 1708   
 1709           int enumHandle = handles.assign(unshared ? unsharedMarker : null);
 1710           ClassNotFoundException resolveEx = desc.getResolveException();
 1711           if (resolveEx != null) {
 1712               handles.markException(enumHandle, resolveEx);
 1713           }
 1714   
 1715           String name = readString(false);
 1716           Enum en = null;
 1717           Class cl = desc.forClass();
 1718           if (cl != null) {
 1719               try {
 1720                   en = Enum.valueOf(cl, name);
 1721               } catch (IllegalArgumentException ex) {
 1722                   throw (IOException) new InvalidObjectException(
 1723                       "enum constant " + name + " does not exist in " +
 1724                       cl).initCause(ex);
 1725               }
 1726               if (!unshared) {
 1727                   handles.setObject(enumHandle, en);
 1728               }
 1729           }
 1730   
 1731           handles.finish(enumHandle);
 1732           passHandle = enumHandle;
 1733           return en;
 1734       }
 1735   
 1736       /**
 1737        * Reads and returns "ordinary" (i.e., not a String, Class,
 1738        * ObjectStreamClass, array, or enum constant) object, or null if object's
 1739        * class is unresolvable (in which case a ClassNotFoundException will be
 1740        * associated with object's handle).  Sets passHandle to object's assigned
 1741        * handle.
 1742        */
 1743       private Object readOrdinaryObject(boolean unshared)
 1744           throws IOException
 1745       {
 1746           if (bin.readByte() != TC_OBJECT) {
 1747               throw new InternalError();
 1748           }
 1749   
 1750           ObjectStreamClass desc = readClassDesc(false);
 1751           desc.checkDeserialize();
 1752   
 1753           Object obj;
 1754           try {
 1755               obj = desc.isInstantiable() ? desc.newInstance() : null;
 1756           } catch (Exception ex) {
 1757               throw (IOException) new InvalidClassException(
 1758                   desc.forClass().getName(),
 1759                   "unable to create instance").initCause(ex);
 1760           }
 1761   
 1762           passHandle = handles.assign(unshared ? unsharedMarker : obj);
 1763           ClassNotFoundException resolveEx = desc.getResolveException();
 1764           if (resolveEx != null) {
 1765               handles.markException(passHandle, resolveEx);
 1766           }
 1767   
 1768           if (desc.isExternalizable()) {
 1769               readExternalData((Externalizable) obj, desc);
 1770           } else {
 1771               readSerialData(obj, desc);
 1772           }
 1773   
 1774           handles.finish(passHandle);
 1775   
 1776           if (obj != null &&
 1777               handles.lookupException(passHandle) == null &&
 1778               desc.hasReadResolveMethod())
 1779           {
 1780               Object rep = desc.invokeReadResolve(obj);
 1781               if (unshared && rep.getClass().isArray()) {
 1782                   rep = cloneArray(rep);
 1783               }
 1784               if (rep != obj) {
 1785                   handles.setObject(passHandle, obj = rep);
 1786               }
 1787           }
 1788   
 1789           return obj;
 1790       }
 1791   
 1792       /**
 1793        * If obj is non-null, reads externalizable data by invoking readExternal()
 1794        * method of obj; otherwise, attempts to skip over externalizable data.
 1795        * Expects that passHandle is set to obj's handle before this method is
 1796        * called.
 1797        */
 1798       private void readExternalData(Externalizable obj, ObjectStreamClass desc)
 1799           throws IOException
 1800       {
 1801           CallbackContext oldContext = curContext;
 1802           curContext = null;
 1803           try {
 1804               boolean blocked = desc.hasBlockExternalData();
 1805               if (blocked) {
 1806                   bin.setBlockDataMode(true);
 1807               }
 1808               if (obj != null) {
 1809                   try {
 1810                       obj.readExternal(this);
 1811                   } catch (ClassNotFoundException ex) {
 1812                       /*
 1813                        * In most cases, the handle table has already propagated
 1814                        * a CNFException to passHandle at this point; this mark
 1815                        * call is included to address cases where the readExternal
 1816                        * method has cons'ed and thrown a new CNFException of its
 1817                        * own.
 1818                        */
 1819                        handles.markException(passHandle, ex);
 1820                   }
 1821               }
 1822               if (blocked) {
 1823                   skipCustomData();
 1824               }
 1825           } finally {
 1826               curContext = oldContext;
 1827           }
 1828           /*
 1829            * At this point, if the externalizable data was not written in
 1830            * block-data form and either the externalizable class doesn't exist
 1831            * locally (i.e., obj == null) or readExternal() just threw a
 1832            * CNFException, then the stream is probably in an inconsistent state,
 1833            * since some (or all) of the externalizable data may not have been
 1834            * consumed.  Since there's no "correct" action to take in this case,
 1835            * we mimic the behavior of past serialization implementations and
 1836            * blindly hope that the stream is in sync; if it isn't and additional
 1837            * externalizable data remains in the stream, a subsequent read will
 1838            * most likely throw a StreamCorruptedException.
 1839            */
 1840       }
 1841   
 1842       /**
 1843        * Reads (or attempts to skip, if obj is null or is tagged with a
 1844        * ClassNotFoundException) instance data for each serializable class of
 1845        * object in stream, from superclass to subclass.  Expects that passHandle
 1846        * is set to obj's handle before this method is called.
 1847        */
 1848       private void readSerialData(Object obj, ObjectStreamClass desc)
 1849           throws IOException
 1850       {
 1851           ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
 1852           for (int i = 0; i < slots.length; i++) {
 1853               ObjectStreamClass slotDesc = slots[i].desc;
 1854   
 1855               if (slots[i].hasData) {
 1856                   if (obj != null &&
 1857                       slotDesc.hasReadObjectMethod() &&
 1858                       handles.lookupException(passHandle) == null)
 1859                   {
 1860                       CallbackContext oldContext = curContext;
 1861   
 1862                       try {
 1863                           curContext = new CallbackContext(obj, slotDesc);
 1864   
 1865                           bin.setBlockDataMode(true);
 1866                           slotDesc.invokeReadObject(obj, this);
 1867                       } catch (ClassNotFoundException ex) {
 1868                           /*
 1869                            * In most cases, the handle table has already
 1870                            * propagated a CNFException to passHandle at this
 1871                            * point; this mark call is included to address cases
 1872                            * where the custom readObject method has cons'ed and
 1873                            * thrown a new CNFException of its own.
 1874                            */
 1875                           handles.markException(passHandle, ex);
 1876                       } finally {
 1877                           curContext.setUsed();
 1878                           curContext = oldContext;
 1879                       }
 1880   
 1881                       /*
 1882                        * defaultDataEnd may have been set indirectly by custom
 1883                        * readObject() method when calling defaultReadObject() or
 1884                        * readFields(); clear it to restore normal read behavior.
 1885                        */
 1886                       defaultDataEnd = false;
 1887                   } else {
 1888                       defaultReadFields(obj, slotDesc);
 1889                   }
 1890                   if (slotDesc.hasWriteObjectData()) {
 1891                       skipCustomData();
 1892                   } else {
 1893                       bin.setBlockDataMode(false);
 1894                   }
 1895               } else {
 1896                   if (obj != null &&
 1897                       slotDesc.hasReadObjectNoDataMethod() &&
 1898                       handles.lookupException(passHandle) == null)
 1899                   {
 1900                       slotDesc.invokeReadObjectNoData(obj);
 1901                   }
 1902               }
 1903           }
 1904       }
 1905   
 1906       /**
 1907        * Skips over all block data and objects until TC_ENDBLOCKDATA is
 1908        * encountered.
 1909        */
 1910       private void skipCustomData() throws IOException {
 1911           int oldHandle = passHandle;
 1912           for (;;) {
 1913               if (bin.getBlockDataMode()) {
 1914                   bin.skipBlockData();
 1915                   bin.setBlockDataMode(false);
 1916               }
 1917               switch (bin.peekByte()) {
 1918                   case TC_BLOCKDATA:
 1919                   case TC_BLOCKDATALONG:
 1920                       bin.setBlockDataMode(true);
 1921                       break;
 1922   
 1923                   case TC_ENDBLOCKDATA:
 1924                       bin.readByte();
 1925                       passHandle = oldHandle;
 1926                       return;
 1927   
 1928                   default:
 1929                       readObject0(false);
 1930                       break;
 1931               }
 1932           }
 1933       }
 1934   
 1935       /**
 1936        * Reads in values of serializable fields declared by given class
 1937        * descriptor.  If obj is non-null, sets field values in obj.  Expects that
 1938        * passHandle is set to obj's handle before this method is called.
 1939        */
 1940       private void defaultReadFields(Object obj, ObjectStreamClass desc)
 1941           throws IOException
 1942       {
 1943           // REMIND: is isInstance check necessary?
 1944           Class cl = desc.forClass();
 1945           if (cl != null && obj != null && !cl.isInstance(obj)) {
 1946               throw new ClassCastException();
 1947           }
 1948   
 1949           int primDataSize = desc.getPrimDataSize();
 1950           if (primVals == null || primVals.length < primDataSize) {
 1951               primVals = new byte[primDataSize];
 1952           }
 1953           bin.readFully(primVals, 0, primDataSize, false);
 1954           if (obj != null) {
 1955               desc.setPrimFieldValues(obj, primVals);
 1956           }
 1957   
 1958           int objHandle = passHandle;
 1959           ObjectStreamField[] fields = desc.getFields(false);
 1960           Object[] objVals = new Object[desc.getNumObjFields()];
 1961           int numPrimFields = fields.length - objVals.length;
 1962           for (int i = 0; i < objVals.length; i++) {
 1963               ObjectStreamField f = fields[numPrimFields + i];
 1964               objVals[i] = readObject0(f.isUnshared());
 1965               if (f.getField() != null) {
 1966                   handles.markDependency(objHandle, passHandle);
 1967               }
 1968           }
 1969           if (obj != null) {
 1970               desc.setObjFieldValues(obj, objVals);
 1971           }
 1972           passHandle = objHandle;
 1973       }
 1974   
 1975       /**
 1976        * Reads in and returns IOException that caused serialization to abort.
 1977        * All stream state is discarded prior to reading in fatal exception.  Sets
 1978        * passHandle to fatal exception's handle.
 1979        */
 1980       private IOException readFatalException() throws IOException {
 1981           if (bin.readByte() != TC_EXCEPTION) {
 1982               throw new InternalError();
 1983           }
 1984           clear();
 1985           return (IOException) readObject0(false);
 1986       }
 1987   
 1988       /**
 1989        * If recursion depth is 0, clears internal data structures; otherwise,
 1990        * throws a StreamCorruptedException.  This method is called when a
 1991        * TC_RESET typecode is encountered.
 1992        */
 1993       private void handleReset() throws StreamCorruptedException {
 1994           if (depth > 0) {
 1995               throw new StreamCorruptedException(
 1996                   "unexpected reset; recursion depth: " + depth);
 1997           }
 1998           clear();
 1999       }
 2000   
 2001       /**
 2002        * Converts specified span of bytes into float values.
 2003        */
 2004       // REMIND: remove once hotspot inlines Float.intBitsToFloat
 2005       private static native void bytesToFloats(byte[] src, int srcpos,
 2006                                                float[] dst, int dstpos,
 2007                                                int nfloats);
 2008   
 2009       /**
 2010        * Converts specified span of bytes into double values.
 2011        */
 2012       // REMIND: remove once hotspot inlines Double.longBitsToDouble
 2013       private static native void bytesToDoubles(byte[] src, int srcpos,
 2014                                                 double[] dst, int dstpos,
 2015                                                 int ndoubles);
 2016   
 2017       /**
 2018        * Returns the first non-null class loader (not counting class loaders of
 2019        * generated reflection implementation classes) up the execution stack, or
 2020        * null if only code from the null class loader is on the stack.  This
 2021        * method is also called via reflection by the following RMI-IIOP class:
 2022        *
 2023        *     com.sun.corba.se.internal.util.JDKClassLoader
 2024        *
 2025        * This method should not be removed or its signature changed without
 2026        * corresponding modifications to the above class.
 2027        */
 2028       // REMIND: change name to something more accurate?
 2029       private static native ClassLoader latestUserDefinedLoader();
 2030   
 2031       /**
 2032        * Default GetField implementation.
 2033        */
 2034       private class GetFieldImpl extends GetField {
 2035   
 2036           /** class descriptor describing serializable fields */
 2037           private final ObjectStreamClass desc;
 2038           /** primitive field values */
 2039           private final byte[] primVals;
 2040           /** object field values */
 2041           private final Object[] objVals;
 2042           /** object field value handles */
 2043           private final int[] objHandles;
 2044   
 2045           /**
 2046            * Creates GetFieldImpl object for reading fields defined in given
 2047            * class descriptor.
 2048            */
 2049           GetFieldImpl(ObjectStreamClass desc) {
 2050               this.desc = desc;
 2051               primVals = new byte[desc.getPrimDataSize()];
 2052               objVals = new Object[desc.getNumObjFields()];
 2053               objHandles = new int[objVals.length];
 2054           }
 2055   
 2056           public ObjectStreamClass getObjectStreamClass() {
 2057               return desc;
 2058           }
 2059   
 2060           public boolean defaulted(String name) throws IOException {
 2061               return (getFieldOffset(name, null) < 0);
 2062           }
 2063   
 2064           public boolean get(String name, boolean val) throws IOException {
 2065               int off = getFieldOffset(name, Boolean.TYPE);
 2066               return (off >= 0) ? Bits.getBoolean(primVals, off) : val;
 2067           }
 2068   
 2069           public byte get(String name, byte val) throws IOException {
 2070               int off = getFieldOffset(name, Byte.TYPE);
 2071               return (off >= 0) ? primVals[off] : val;
 2072           }
 2073   
 2074           public char get(String name, char val) throws IOException {
 2075               int off = getFieldOffset(name, Character.TYPE);
 2076               return (off >= 0) ? Bits.getChar(primVals, off) : val;
 2077           }
 2078   
 2079           public short get(String name, short val) throws IOException {
 2080               int off = getFieldOffset(name, Short.TYPE);
 2081               return (off >= 0) ? Bits.getShort(primVals, off) : val;
 2082           }
 2083   
 2084           public int get(String name, int val) throws IOException {
 2085               int off = getFieldOffset(name, Integer.TYPE);
 2086               return (off >= 0) ? Bits.getInt(primVals, off) : val;
 2087           }
 2088   
 2089           public float get(String name, float val) throws IOException {
 2090               int off = getFieldOffset(name, Float.TYPE);
 2091               return (off >= 0) ? Bits.getFloat(primVals, off) : val;
 2092           }
 2093   
 2094           public long get(String name, long val) throws IOException {
 2095               int off = getFieldOffset(name, Long.TYPE);
 2096               return (off >= 0) ? Bits.getLong(primVals, off) : val;
 2097           }
 2098   
 2099           public double get(String name, double val) throws IOException {
 2100               int off = getFieldOffset(name, Double.TYPE);
 2101               return (off >= 0) ? Bits.getDouble(primVals, off) : val;
 2102           }
 2103   
 2104           public Object get(String name, Object val) throws IOException {
 2105               int off = getFieldOffset(name, Object.class);
 2106               if (off >= 0) {
 2107                   int objHandle = objHandles[off];
 2108                   handles.markDependency(passHandle, objHandle);
 2109                   return (handles.lookupException(objHandle) == null) ?
 2110                       objVals[off] : null;
 2111               } else {
 2112                   return val;
 2113               }
 2114           }
 2115   
 2116           /**
 2117            * Reads primitive and object field values from stream.
 2118            */
 2119           void readFields() throws IOException {
 2120               bin.readFully(primVals, 0, primVals.length, false);
 2121   
 2122               int oldHandle = passHandle;
 2123               ObjectStreamField[] fields = desc.getFields(false);
 2124               int numPrimFields = fields.length - objVals.length;
 2125               for (int i = 0; i < objVals.length; i++) {
 2126                   objVals[i] =
 2127                       readObject0(fields[numPrimFields + i].isUnshared());
 2128                   objHandles[i] = passHandle;
 2129               }
 2130               passHandle = oldHandle;
 2131           }
 2132   
 2133           /**
 2134            * Returns offset of field with given name and type.  A specified type
 2135            * of null matches all types, Object.class matches all non-primitive
 2136            * types, and any other non-null type matches assignable types only.
 2137            * If no matching field is found in the (incoming) class
 2138            * descriptor but a matching field is present in the associated local
 2139            * class descriptor, returns -1.  Throws IllegalArgumentException if
 2140            * neither incoming nor local class descriptor contains a match.
 2141            */
 2142           private int getFieldOffset(String name, Class type) {
 2143               ObjectStreamField field = desc.getField(name, type);
 2144               if (field != null) {
 2145                   return field.getOffset();
 2146               } else if (desc.getLocalDesc().getField(name, type) != null) {
 2147                   return -1;
 2148               } else {
 2149                   throw new IllegalArgumentException("no such field " + name +
 2150                                                      " with type " + type);
 2151               }
 2152           }
 2153       }
 2154   
 2155       /**
 2156        * Prioritized list of callbacks to be performed once object graph has been
 2157        * completely deserialized.
 2158        */
 2159       private static class ValidationList {
 2160   
 2161           private static class Callback {
 2162               final ObjectInputValidation obj;
 2163               final int priority;
 2164               Callback next;
 2165               final AccessControlContext acc;
 2166   
 2167               Callback(ObjectInputValidation obj, int priority, Callback next,
 2168                   AccessControlContext acc)
 2169               {
 2170                   this.obj = obj;
 2171                   this.priority = priority;
 2172                   this.next = next;
 2173                   this.acc = acc;
 2174               }
 2175           }
 2176   
 2177           /** linked list of callbacks */
 2178           private Callback list;
 2179   
 2180           /**
 2181            * Creates new (empty) ValidationList.
 2182            */
 2183           ValidationList() {
 2184           }
 2185   
 2186           /**
 2187            * Registers callback.  Throws InvalidObjectException if callback
 2188            * object is null.
 2189            */
 2190           void register(ObjectInputValidation obj, int priority)
 2191               throws InvalidObjectException
 2192           {
 2193               if (obj == null) {
 2194                   throw new InvalidObjectException("null callback");
 2195               }
 2196   
 2197               Callback prev = null, cur = list;
 2198               while (cur != null && priority < cur.priority) {
 2199                   prev = cur;
 2200                   cur = cur.next;
 2201               }
 2202               AccessControlContext acc = AccessController.getContext();
 2203               if (prev != null) {
 2204                   prev.next = new Callback(obj, priority, cur, acc);
 2205               } else {
 2206                   list = new Callback(obj, priority, list, acc);
 2207               }
 2208           }
 2209   
 2210           /**
 2211            * Invokes all registered callbacks and clears the callback list.
 2212            * Callbacks with higher priorities are called first; those with equal
 2213            * priorities may be called in any order.  If any of the callbacks
 2214            * throws an InvalidObjectException, the callback process is terminated
 2215            * and the exception propagated upwards.
 2216            */
 2217           void doCallbacks() throws InvalidObjectException {
 2218               try {
 2219                   while (list != null) {
 2220                       AccessController.doPrivileged(
 2221                           new PrivilegedExceptionAction<Void>()
 2222                       {
 2223                           public Void run() throws InvalidObjectException {
 2224                               list.obj.validateObject();
 2225                               return null;
 2226                           }
 2227                       }, list.acc);
 2228                       list = list.next;
 2229                   }
 2230               } catch (PrivilegedActionException ex) {
 2231                   list = null;
 2232                   throw (InvalidObjectException) ex.getException();
 2233               }
 2234           }
 2235   
 2236           /**
 2237            * Resets the callback list to its initial (empty) state.
 2238            */
 2239           public void clear() {
 2240               list = null;
 2241           }
 2242       }
 2243   
 2244       /**
 2245        * Input stream supporting single-byte peek operations.
 2246        */
 2247       private static class PeekInputStream extends InputStream {
 2248   
 2249           /** underlying stream */
 2250           private final InputStream in;
 2251           /** peeked byte */
 2252           private int peekb = -1;
 2253   
 2254           /**
 2255            * Creates new PeekInputStream on top of given underlying stream.
 2256            */
 2257           PeekInputStream(InputStream in) {
 2258               this.in = in;
 2259           }
 2260   
 2261           /**
 2262            * Peeks at next byte value in stream.  Similar to read(), except
 2263            * that it does not consume the read value.
 2264            */
 2265           int peek() throws IOException {
 2266               return (peekb >= 0) ? peekb : (peekb = in.read());
 2267           }
 2268   
 2269           public int read() throws IOException {
 2270               if (peekb >= 0) {
 2271                   int v = peekb;
 2272                   peekb = -1;
 2273                   return v;
 2274               } else {
 2275                   return in.read();
 2276               }
 2277           }
 2278   
 2279           public int read(byte[] b, int off, int len) throws IOException {
 2280               if (len == 0) {
 2281                   return 0;
 2282               } else if (peekb < 0) {
 2283                   return in.read(b, off, len);
 2284               } else {
 2285                   b[off++] = (byte) peekb;
 2286                   len--;
 2287                   peekb = -1;
 2288                   int n = in.read(b, off, len);
 2289                   return (n >= 0) ? (n + 1) : 1;
 2290               }
 2291           }
 2292   
 2293           void readFully(byte[] b, int off, int len) throws IOException {
 2294               int n = 0;
 2295