emul/compact/src/main/java/java/io/ObjectInputStream.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Mon, 28 Jan 2013 18:12:47 +0100
branchjdk7-b147
changeset 601 5198affdb915
child 604 3fcc279c921b
permissions -rw-r--r--
Adding ObjectInputStream and ObjectOutputStream (but without implementation). Adding PropertyChange related classes.
     1 /*
     2  * Copyright (c) 1996, 2010, Oracle and/or its affiliates. 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.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * 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<>(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<>();
   233 
   234         /** queue for WeakReferences to audited subclasses */
   235         static final ReferenceQueue<Class<?>> subclassAuditsQueue =
   236             new ReferenceQueue<>();
   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 SerialCallbackContext 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         SerialCallbackContext 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                     SerialCallbackContext oldContext = curContext;
  1861 
  1862                     try {
  1863                         curContext = new SerialCallbackContext(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             while (n < len) {
  2296                 int count = read(b, off + n, len - n);
  2297                 if (count < 0) {
  2298                     throw new EOFException();
  2299                 }
  2300                 n += count;
  2301             }
  2302         }
  2303 
  2304         public long skip(long n) throws IOException {
  2305             if (n <= 0) {
  2306                 return 0;
  2307             }
  2308             int skipped = 0;
  2309             if (peekb >= 0) {
  2310                 peekb = -1;
  2311                 skipped++;
  2312                 n--;
  2313             }
  2314             return skipped + skip(n);
  2315         }
  2316 
  2317         public int available() throws IOException {
  2318             return in.available() + ((peekb >= 0) ? 1 : 0);
  2319         }
  2320 
  2321         public void close() throws IOException {
  2322             in.close();
  2323         }
  2324     }
  2325 
  2326     /**
  2327      * Input stream with two modes: in default mode, inputs data written in the
  2328      * same format as DataOutputStream; in "block data" mode, inputs data
  2329      * bracketed by block data markers (see object serialization specification
  2330      * for details).  Buffering depends on block data mode: when in default
  2331      * mode, no data is buffered in advance; when in block data mode, all data
  2332      * for the current data block is read in at once (and buffered).
  2333      */
  2334     private class BlockDataInputStream
  2335         extends InputStream implements DataInput
  2336     {
  2337         /** maximum data block length */
  2338         private static final int MAX_BLOCK_SIZE = 1024;
  2339         /** maximum data block header length */
  2340         private static final int MAX_HEADER_SIZE = 5;
  2341         /** (tunable) length of char buffer (for reading strings) */
  2342         private static final int CHAR_BUF_SIZE = 256;
  2343         /** readBlockHeader() return value indicating header read may block */
  2344         private static final int HEADER_BLOCKED = -2;
  2345 
  2346         /** buffer for reading general/block data */
  2347         private final byte[] buf = new byte[MAX_BLOCK_SIZE];
  2348         /** buffer for reading block data headers */
  2349         private final byte[] hbuf = new byte[MAX_HEADER_SIZE];
  2350         /** char buffer for fast string reads */
  2351         private final char[] cbuf = new char[CHAR_BUF_SIZE];
  2352 
  2353         /** block data mode */
  2354         private boolean blkmode = false;
  2355 
  2356         // block data state fields; values meaningful only when blkmode true
  2357         /** current offset into buf */
  2358         private int pos = 0;
  2359         /** end offset of valid data in buf, or -1 if no more block data */
  2360         private int end = -1;
  2361         /** number of bytes in current block yet to be read from stream */
  2362         private int unread = 0;
  2363 
  2364         /** underlying stream (wrapped in peekable filter stream) */
  2365         private final PeekInputStream in;
  2366         /** loopback stream (for data reads that span data blocks) */
  2367         private final DataInputStream din;
  2368 
  2369         /**
  2370          * Creates new BlockDataInputStream on top of given underlying stream.
  2371          * Block data mode is turned off by default.
  2372          */
  2373         BlockDataInputStream(InputStream in) {
  2374             this.in = new PeekInputStream(in);
  2375             din = new DataInputStream(this);
  2376         }
  2377 
  2378         /**
  2379          * Sets block data mode to the given mode (true == on, false == off)
  2380          * and returns the previous mode value.  If the new mode is the same as
  2381          * the old mode, no action is taken.  Throws IllegalStateException if
  2382          * block data mode is being switched from on to off while unconsumed
  2383          * block data is still present in the stream.
  2384          */
  2385         boolean setBlockDataMode(boolean newmode) throws IOException {
  2386             if (blkmode == newmode) {
  2387                 return blkmode;
  2388             }
  2389             if (newmode) {
  2390                 pos = 0;
  2391                 end = 0;
  2392                 unread = 0;
  2393             } else if (pos < end) {
  2394                 throw new IllegalStateException("unread block data");
  2395             }
  2396             blkmode = newmode;
  2397             return !blkmode;
  2398         }
  2399 
  2400         /**
  2401          * Returns true if the stream is currently in block data mode, false
  2402          * otherwise.
  2403          */
  2404         boolean getBlockDataMode() {
  2405             return blkmode;
  2406         }
  2407 
  2408         /**
  2409          * If in block data mode, skips to the end of the current group of data
  2410          * blocks (but does not unset block data mode).  If not in block data
  2411          * mode, throws an IllegalStateException.
  2412          */
  2413         void skipBlockData() throws IOException {
  2414             if (!blkmode) {
  2415                 throw new IllegalStateException("not in block data mode");
  2416             }
  2417             while (end >= 0) {
  2418                 refill();
  2419             }
  2420         }
  2421 
  2422         /**
  2423          * Attempts to read in the next block data header (if any).  If
  2424          * canBlock is false and a full header cannot be read without possibly
  2425          * blocking, returns HEADER_BLOCKED, else if the next element in the
  2426          * stream is a block data header, returns the block data length
  2427          * specified by the header, else returns -1.
  2428          */
  2429         private int readBlockHeader(boolean canBlock) throws IOException {
  2430             if (defaultDataEnd) {
  2431                 /*
  2432                  * Fix for 4360508: stream is currently at the end of a field
  2433                  * value block written via default serialization; since there
  2434                  * is no terminating TC_ENDBLOCKDATA tag, simulate
  2435                  * end-of-custom-data behavior explicitly.
  2436                  */
  2437                 return -1;
  2438             }
  2439             try {
  2440                 for (;;) {
  2441                     int avail = canBlock ? Integer.MAX_VALUE : in.available();
  2442                     if (avail == 0) {
  2443                         return HEADER_BLOCKED;
  2444                     }
  2445 
  2446                     int tc = in.peek();
  2447                     switch (tc) {
  2448                         case TC_BLOCKDATA:
  2449                             if (avail < 2) {
  2450                                 return HEADER_BLOCKED;
  2451                             }
  2452                             in.readFully(hbuf, 0, 2);
  2453                             return hbuf[1] & 0xFF;
  2454 
  2455                         case TC_BLOCKDATALONG:
  2456                             if (avail < 5) {
  2457                                 return HEADER_BLOCKED;
  2458                             }
  2459                             in.readFully(hbuf, 0, 5);
  2460                             int len = Bits.getInt(hbuf, 1);
  2461                             if (len < 0) {
  2462                                 throw new StreamCorruptedException(
  2463                                     "illegal block data header length: " +
  2464                                     len);
  2465                             }
  2466                             return len;
  2467 
  2468                         /*
  2469                          * TC_RESETs may occur in between data blocks.
  2470                          * Unfortunately, this case must be parsed at a lower
  2471                          * level than other typecodes, since primitive data
  2472                          * reads may span data blocks separated by a TC_RESET.
  2473                          */
  2474                         case TC_RESET:
  2475                             in.read();
  2476                             handleReset();
  2477                             break;
  2478 
  2479                         default:
  2480                             if (tc >= 0 && (tc < TC_BASE || tc > TC_MAX)) {
  2481                                 throw new StreamCorruptedException(
  2482                                     String.format("invalid type code: %02X",
  2483                                     tc));
  2484                             }
  2485                             return -1;
  2486                     }
  2487                 }
  2488             } catch (EOFException ex) {
  2489                 throw new StreamCorruptedException(
  2490                     "unexpected EOF while reading block data header");
  2491             }
  2492         }
  2493 
  2494         /**
  2495          * Refills internal buffer buf with block data.  Any data in buf at the
  2496          * time of the call is considered consumed.  Sets the pos, end, and
  2497          * unread fields to reflect the new amount of available block data; if
  2498          * the next element in the stream is not a data block, sets pos and
  2499          * unread to 0 and end to -1.
  2500          */
  2501         private void refill() throws IOException {
  2502             try {
  2503                 do {
  2504                     pos = 0;
  2505                     if (unread > 0) {
  2506                         int n =
  2507                             in.read(buf, 0, Math.min(unread, MAX_BLOCK_SIZE));
  2508                         if (n >= 0) {
  2509                             end = n;
  2510                             unread -= n;
  2511                         } else {
  2512                             throw new StreamCorruptedException(
  2513                                 "unexpected EOF in middle of data block");
  2514                         }
  2515                     } else {
  2516                         int n = readBlockHeader(true);
  2517                         if (n >= 0) {
  2518                             end = 0;
  2519                             unread = n;
  2520                         } else {
  2521                             end = -1;
  2522                             unread = 0;
  2523                         }
  2524                     }
  2525                 } while (pos == end);
  2526             } catch (IOException ex) {
  2527                 pos = 0;
  2528                 end = -1;
  2529                 unread = 0;
  2530                 throw ex;
  2531             }
  2532         }
  2533 
  2534         /**
  2535          * If in block data mode, returns the number of unconsumed bytes
  2536          * remaining in the current data block.  If not in block data mode,
  2537          * throws an IllegalStateException.
  2538          */
  2539         int currentBlockRemaining() {
  2540             if (blkmode) {
  2541                 return (end >= 0) ? (end - pos) + unread : 0;
  2542             } else {
  2543                 throw new IllegalStateException();
  2544             }
  2545         }
  2546 
  2547         /**
  2548          * Peeks at (but does not consume) and returns the next byte value in
  2549          * the stream, or -1 if the end of the stream/block data (if in block
  2550          * data mode) has been reached.
  2551          */
  2552         int peek() throws IOException {
  2553             if (blkmode) {
  2554                 if (pos == end) {
  2555                     refill();
  2556                 }
  2557                 return (end >= 0) ? (buf[pos] & 0xFF) : -1;
  2558             } else {
  2559                 return in.peek();
  2560             }
  2561         }
  2562 
  2563         /**
  2564          * Peeks at (but does not consume) and returns the next byte value in
  2565          * the stream, or throws EOFException if end of stream/block data has
  2566          * been reached.
  2567          */
  2568         byte peekByte() throws IOException {
  2569             int val = peek();
  2570             if (val < 0) {
  2571                 throw new EOFException();
  2572             }
  2573             return (byte) val;
  2574         }
  2575 
  2576 
  2577         /* ----------------- generic input stream methods ------------------ */
  2578         /*
  2579          * The following methods are equivalent to their counterparts in
  2580          * InputStream, except that they interpret data block boundaries and
  2581          * read the requested data from within data blocks when in block data
  2582          * mode.
  2583          */
  2584 
  2585         public int read() throws IOException {
  2586             if (blkmode) {
  2587                 if (pos == end) {
  2588                     refill();
  2589                 }
  2590                 return (end >= 0) ? (buf[pos++] & 0xFF) : -1;
  2591             } else {
  2592                 return in.read();
  2593             }
  2594         }
  2595 
  2596         public int read(byte[] b, int off, int len) throws IOException {
  2597             return read(b, off, len, false);
  2598         }
  2599 
  2600         public long skip(long len) throws IOException {
  2601             long remain = len;
  2602             while (remain > 0) {
  2603                 if (blkmode) {
  2604                     if (pos == end) {
  2605                         refill();
  2606                     }
  2607                     if (end < 0) {
  2608                         break;
  2609                     }
  2610                     int nread = (int) Math.min(remain, end - pos);
  2611                     remain -= nread;
  2612                     pos += nread;
  2613                 } else {
  2614                     int nread = (int) Math.min(remain, MAX_BLOCK_SIZE);
  2615                     if ((nread = in.read(buf, 0, nread)) < 0) {
  2616                         break;
  2617                     }
  2618                     remain -= nread;
  2619                 }
  2620             }
  2621             return len - remain;
  2622         }
  2623 
  2624         public int available() throws IOException {
  2625             if (blkmode) {
  2626                 if ((pos == end) && (unread == 0)) {
  2627                     int n;
  2628                     while ((n = readBlockHeader(false)) == 0) ;
  2629                     switch (n) {
  2630                         case HEADER_BLOCKED:
  2631                             break;
  2632 
  2633                         case -1:
  2634                             pos = 0;
  2635                             end = -1;
  2636                             break;
  2637 
  2638                         default:
  2639                             pos = 0;
  2640                             end = 0;
  2641                             unread = n;
  2642                             break;
  2643                     }
  2644                 }
  2645                 // avoid unnecessary call to in.available() if possible
  2646                 int unreadAvail = (unread > 0) ?
  2647                     Math.min(in.available(), unread) : 0;
  2648                 return (end >= 0) ? (end - pos) + unreadAvail : 0;
  2649             } else {
  2650                 return in.available();
  2651             }
  2652         }
  2653 
  2654         public void close() throws IOException {
  2655             if (blkmode) {
  2656                 pos = 0;
  2657                 end = -1;
  2658                 unread = 0;
  2659             }
  2660             in.close();
  2661         }
  2662 
  2663         /**
  2664          * Attempts to read len bytes into byte array b at offset off.  Returns
  2665          * the number of bytes read, or -1 if the end of stream/block data has
  2666          * been reached.  If copy is true, reads values into an intermediate
  2667          * buffer before copying them to b (to avoid exposing a reference to
  2668          * b).
  2669          */
  2670         int read(byte[] b, int off, int len, boolean copy) throws IOException {
  2671             if (len == 0) {
  2672                 return 0;
  2673             } else if (blkmode) {
  2674                 if (pos == end) {
  2675                     refill();
  2676                 }
  2677                 if (end < 0) {
  2678                     return -1;
  2679                 }
  2680                 int nread = Math.min(len, end - pos);
  2681                 System.arraycopy(buf, pos, b, off, nread);
  2682                 pos += nread;
  2683                 return nread;
  2684             } else if (copy) {
  2685                 int nread = in.read(buf, 0, Math.min(len, MAX_BLOCK_SIZE));
  2686                 if (nread > 0) {
  2687                     System.arraycopy(buf, 0, b, off, nread);
  2688                 }
  2689                 return nread;
  2690             } else {
  2691                 return in.read(b, off, len);
  2692             }
  2693         }
  2694 
  2695         /* ----------------- primitive data input methods ------------------ */
  2696         /*
  2697          * The following methods are equivalent to their counterparts in
  2698          * DataInputStream, except that they interpret data block boundaries
  2699          * and read the requested data from within data blocks when in block
  2700          * data mode.
  2701          */
  2702 
  2703         public void readFully(byte[] b) throws IOException {
  2704             readFully(b, 0, b.length, false);
  2705         }
  2706 
  2707         public void readFully(byte[] b, int off, int len) throws IOException {
  2708             readFully(b, off, len, false);
  2709         }
  2710 
  2711         public void readFully(byte[] b, int off, int len, boolean copy)
  2712             throws IOException
  2713         {
  2714             while (len > 0) {
  2715                 int n = read(b, off, len, copy);
  2716                 if (n < 0) {
  2717                     throw new EOFException();
  2718                 }
  2719                 off += n;
  2720                 len -= n;
  2721             }
  2722         }
  2723 
  2724         public int skipBytes(int n) throws IOException {
  2725             return din.skipBytes(n);
  2726         }
  2727 
  2728         public boolean readBoolean() throws IOException {
  2729             int v = read();
  2730             if (v < 0) {
  2731                 throw new EOFException();
  2732             }
  2733             return (v != 0);
  2734         }
  2735 
  2736         public byte readByte() throws IOException {
  2737             int v = read();
  2738             if (v < 0) {
  2739                 throw new EOFException();
  2740             }
  2741             return (byte) v;
  2742         }
  2743 
  2744         public int readUnsignedByte() throws IOException {
  2745             int v = read();
  2746             if (v < 0) {
  2747                 throw new EOFException();
  2748             }
  2749             return v;
  2750         }
  2751 
  2752         public char readChar() throws IOException {
  2753             if (!blkmode) {
  2754                 pos = 0;
  2755                 in.readFully(buf, 0, 2);
  2756             } else if (end - pos < 2) {
  2757                 return din.readChar();
  2758             }
  2759             char v = Bits.getChar(buf, pos);
  2760             pos += 2;
  2761             return v;
  2762         }
  2763 
  2764         public short readShort() throws IOException {
  2765             if (!blkmode) {
  2766                 pos = 0;
  2767                 in.readFully(buf, 0, 2);
  2768             } else if (end - pos < 2) {
  2769                 return din.readShort();
  2770             }
  2771             short v = Bits.getShort(buf, pos);
  2772             pos += 2;
  2773             return v;
  2774         }
  2775 
  2776         public int readUnsignedShort() throws IOException {
  2777             if (!blkmode) {
  2778                 pos = 0;
  2779                 in.readFully(buf, 0, 2);
  2780             } else if (end - pos < 2) {
  2781                 return din.readUnsignedShort();
  2782             }
  2783             int v = Bits.getShort(buf, pos) & 0xFFFF;
  2784             pos += 2;
  2785             return v;
  2786         }
  2787 
  2788         public int readInt() throws IOException {
  2789             if (!blkmode) {
  2790                 pos = 0;
  2791                 in.readFully(buf, 0, 4);
  2792             } else if (end - pos < 4) {
  2793                 return din.readInt();
  2794             }
  2795             int v = Bits.getInt(buf, pos);
  2796             pos += 4;
  2797             return v;
  2798         }
  2799 
  2800         public float readFloat() throws IOException {
  2801             if (!blkmode) {
  2802                 pos = 0;
  2803                 in.readFully(buf, 0, 4);
  2804             } else if (end - pos < 4) {
  2805                 return din.readFloat();
  2806             }
  2807             float v = Bits.getFloat(buf, pos);
  2808             pos += 4;
  2809             return v;
  2810         }
  2811 
  2812         public long readLong() throws IOException {
  2813             if (!blkmode) {
  2814                 pos = 0;
  2815                 in.readFully(buf, 0, 8);
  2816             } else if (end - pos < 8) {
  2817                 return din.readLong();
  2818             }
  2819             long v = Bits.getLong(buf, pos);
  2820             pos += 8;
  2821             return v;
  2822         }
  2823 
  2824         public double readDouble() throws IOException {
  2825             if (!blkmode) {
  2826                 pos = 0;
  2827                 in.readFully(buf, 0, 8);
  2828             } else if (end - pos < 8) {
  2829                 return din.readDouble();
  2830             }
  2831             double v = Bits.getDouble(buf, pos);
  2832             pos += 8;
  2833             return v;
  2834         }
  2835 
  2836         public String readUTF() throws IOException {
  2837             return readUTFBody(readUnsignedShort());
  2838         }
  2839 
  2840         public String readLine() throws IOException {
  2841             return din.readLine();      // deprecated, not worth optimizing
  2842         }
  2843 
  2844         /* -------------- primitive data array input methods --------------- */
  2845         /*
  2846          * The following methods read in spans of primitive data values.
  2847          * Though equivalent to calling the corresponding primitive read
  2848          * methods repeatedly, these methods are optimized for reading groups
  2849          * of primitive data values more efficiently.
  2850          */
  2851 
  2852         void readBooleans(boolean[] v, int off, int len) throws IOException {
  2853             int stop, endoff = off + len;
  2854             while (off < endoff) {
  2855                 if (!blkmode) {
  2856                     int span = Math.min(endoff - off, MAX_BLOCK_SIZE);
  2857                     in.readFully(buf, 0, span);
  2858                     stop = off + span;
  2859                     pos = 0;
  2860                 } else if (end - pos < 1) {
  2861                     v[off++] = din.readBoolean();
  2862                     continue;
  2863                 } else {
  2864                     stop = Math.min(endoff, off + end - pos);
  2865                 }
  2866 
  2867                 while (off < stop) {
  2868                     v[off++] = Bits.getBoolean(buf, pos++);
  2869                 }
  2870             }
  2871         }
  2872 
  2873         void readChars(char[] v, int off, int len) throws IOException {
  2874             int stop, endoff = off + len;
  2875             while (off < endoff) {
  2876                 if (!blkmode) {
  2877                     int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 1);
  2878                     in.readFully(buf, 0, span << 1);
  2879                     stop = off + span;
  2880                     pos = 0;
  2881                 } else if (end - pos < 2) {
  2882                     v[off++] = din.readChar();
  2883                     continue;
  2884                 } else {
  2885                     stop = Math.min(endoff, off + ((end - pos) >> 1));
  2886                 }
  2887 
  2888                 while (off < stop) {
  2889                     v[off++] = Bits.getChar(buf, pos);
  2890                     pos += 2;
  2891                 }
  2892             }
  2893         }
  2894 
  2895         void readShorts(short[] v, int off, int len) throws IOException {
  2896             int stop, endoff = off + len;
  2897             while (off < endoff) {
  2898                 if (!blkmode) {
  2899                     int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 1);
  2900                     in.readFully(buf, 0, span << 1);
  2901                     stop = off + span;
  2902                     pos = 0;
  2903                 } else if (end - pos < 2) {
  2904                     v[off++] = din.readShort();
  2905                     continue;
  2906                 } else {
  2907                     stop = Math.min(endoff, off + ((end - pos) >> 1));
  2908                 }
  2909 
  2910                 while (off < stop) {
  2911                     v[off++] = Bits.getShort(buf, pos);
  2912                     pos += 2;
  2913                 }
  2914             }
  2915         }
  2916 
  2917         void readInts(int[] v, int off, int len) throws IOException {
  2918             int stop, endoff = off + len;
  2919             while (off < endoff) {
  2920                 if (!blkmode) {
  2921                     int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 2);
  2922                     in.readFully(buf, 0, span << 2);
  2923                     stop = off + span;
  2924                     pos = 0;
  2925                 } else if (end - pos < 4) {
  2926                     v[off++] = din.readInt();
  2927                     continue;
  2928                 } else {
  2929                     stop = Math.min(endoff, off + ((end - pos) >> 2));
  2930                 }
  2931 
  2932                 while (off < stop) {
  2933                     v[off++] = Bits.getInt(buf, pos);
  2934                     pos += 4;
  2935                 }
  2936             }
  2937         }
  2938 
  2939         void readFloats(float[] v, int off, int len) throws IOException {
  2940             int span, endoff = off + len;
  2941             while (off < endoff) {
  2942                 if (!blkmode) {
  2943                     span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 2);
  2944                     in.readFully(buf, 0, span << 2);
  2945                     pos = 0;
  2946                 } else if (end - pos < 4) {
  2947                     v[off++] = din.readFloat();
  2948                     continue;
  2949                 } else {
  2950                     span = Math.min(endoff - off, ((end - pos) >> 2));
  2951                 }
  2952 
  2953                 bytesToFloats(buf, pos, v, off, span);
  2954                 off += span;
  2955                 pos += span << 2;
  2956             }
  2957         }
  2958 
  2959         void readLongs(long[] v, int off, int len) throws IOException {
  2960             int stop, endoff = off + len;
  2961             while (off < endoff) {
  2962                 if (!blkmode) {
  2963                     int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 3);
  2964                     in.readFully(buf, 0, span << 3);
  2965                     stop = off + span;
  2966                     pos = 0;
  2967                 } else if (end - pos < 8) {
  2968                     v[off++] = din.readLong();
  2969                     continue;
  2970                 } else {
  2971                     stop = Math.min(endoff, off + ((end - pos) >> 3));
  2972                 }
  2973 
  2974                 while (off < stop) {
  2975                     v[off++] = Bits.getLong(buf, pos);
  2976                     pos += 8;
  2977                 }
  2978             }
  2979         }
  2980 
  2981         void readDoubles(double[] v, int off, int len) throws IOException {
  2982             int span, endoff = off + len;
  2983             while (off < endoff) {
  2984                 if (!blkmode) {
  2985                     span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 3);
  2986                     in.readFully(buf, 0, span << 3);
  2987                     pos = 0;
  2988                 } else if (end - pos < 8) {
  2989                     v[off++] = din.readDouble();
  2990                     continue;
  2991                 } else {
  2992                     span = Math.min(endoff - off, ((end - pos) >> 3));
  2993                 }
  2994 
  2995                 bytesToDoubles(buf, pos, v, off, span);
  2996                 off += span;
  2997                 pos += span << 3;
  2998             }
  2999         }
  3000 
  3001         /**
  3002          * Reads in string written in "long" UTF format.  "Long" UTF format is
  3003          * identical to standard UTF, except that it uses an 8 byte header
  3004          * (instead of the standard 2 bytes) to convey the UTF encoding length.
  3005          */
  3006         String readLongUTF() throws IOException {
  3007             return readUTFBody(readLong());
  3008         }
  3009 
  3010         /**
  3011          * Reads in the "body" (i.e., the UTF representation minus the 2-byte
  3012          * or 8-byte length header) of a UTF encoding, which occupies the next
  3013          * utflen bytes.
  3014          */
  3015         private String readUTFBody(long utflen) throws IOException {
  3016             StringBuilder sbuf = new StringBuilder();
  3017             if (!blkmode) {
  3018                 end = pos = 0;
  3019             }
  3020 
  3021             while (utflen > 0) {
  3022                 int avail = end - pos;
  3023                 if (avail >= 3 || (long) avail == utflen) {
  3024                     utflen -= readUTFSpan(sbuf, utflen);
  3025                 } else {
  3026                     if (blkmode) {
  3027                         // near block boundary, read one byte at a time
  3028                         utflen -= readUTFChar(sbuf, utflen);
  3029                     } else {
  3030                         // shift and refill buffer manually
  3031                         if (avail > 0) {
  3032                             System.arraycopy(buf, pos, buf, 0, avail);
  3033                         }
  3034                         pos = 0;
  3035                         end = (int) Math.min(MAX_BLOCK_SIZE, utflen);
  3036                         in.readFully(buf, avail, end - avail);
  3037                     }
  3038                 }
  3039             }
  3040 
  3041             return sbuf.toString();
  3042         }
  3043 
  3044         /**
  3045          * Reads span of UTF-encoded characters out of internal buffer
  3046          * (starting at offset pos and ending at or before offset end),
  3047          * consuming no more than utflen bytes.  Appends read characters to
  3048          * sbuf.  Returns the number of bytes consumed.
  3049          */
  3050         private long readUTFSpan(StringBuilder sbuf, long utflen)
  3051             throws IOException
  3052         {
  3053             int cpos = 0;
  3054             int start = pos;
  3055             int avail = Math.min(end - pos, CHAR_BUF_SIZE);
  3056             // stop short of last char unless all of utf bytes in buffer
  3057             int stop = pos + ((utflen > avail) ? avail - 2 : (int) utflen);
  3058             boolean outOfBounds = false;
  3059 
  3060             try {
  3061                 while (pos < stop) {
  3062                     int b1, b2, b3;
  3063                     b1 = buf[pos++] & 0xFF;
  3064                     switch (b1 >> 4) {
  3065                         case 0:
  3066                         case 1:
  3067                         case 2:
  3068                         case 3:
  3069                         case 4:
  3070                         case 5:
  3071                         case 6:
  3072                         case 7:   // 1 byte format: 0xxxxxxx
  3073                             cbuf[cpos++] = (char) b1;
  3074                             break;
  3075 
  3076                         case 12:
  3077                         case 13:  // 2 byte format: 110xxxxx 10xxxxxx
  3078                             b2 = buf[pos++];
  3079                             if ((b2 & 0xC0) != 0x80) {
  3080                                 throw new UTFDataFormatException();
  3081                             }
  3082                             cbuf[cpos++] = (char) (((b1 & 0x1F) << 6) |
  3083                                                    ((b2 & 0x3F) << 0));
  3084                             break;
  3085 
  3086                         case 14:  // 3 byte format: 1110xxxx 10xxxxxx 10xxxxxx
  3087                             b3 = buf[pos + 1];
  3088                             b2 = buf[pos + 0];
  3089                             pos += 2;
  3090                             if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) {
  3091                                 throw new UTFDataFormatException();
  3092                             }
  3093                             cbuf[cpos++] = (char) (((b1 & 0x0F) << 12) |
  3094                                                    ((b2 & 0x3F) << 6) |
  3095                                                    ((b3 & 0x3F) << 0));
  3096                             break;
  3097 
  3098                         default:  // 10xx xxxx, 1111 xxxx
  3099                             throw new UTFDataFormatException();
  3100                     }
  3101                 }
  3102             } catch (ArrayIndexOutOfBoundsException ex) {
  3103                 outOfBounds = true;
  3104             } finally {
  3105                 if (outOfBounds || (pos - start) > utflen) {
  3106                     /*
  3107                      * Fix for 4450867: if a malformed utf char causes the
  3108                      * conversion loop to scan past the expected end of the utf
  3109                      * string, only consume the expected number of utf bytes.
  3110                      */
  3111                     pos = start + (int) utflen;
  3112                     throw new UTFDataFormatException();
  3113                 }
  3114             }
  3115 
  3116             sbuf.append(cbuf, 0, cpos);
  3117             return pos - start;
  3118         }
  3119 
  3120         /**
  3121          * Reads in single UTF-encoded character one byte at a time, appends
  3122          * the character to sbuf, and returns the number of bytes consumed.
  3123          * This method is used when reading in UTF strings written in block
  3124          * data mode to handle UTF-encoded characters which (potentially)
  3125          * straddle block-data boundaries.
  3126          */
  3127         private int readUTFChar(StringBuilder sbuf, long utflen)
  3128             throws IOException
  3129         {
  3130             int b1, b2, b3;
  3131             b1 = readByte() & 0xFF;
  3132             switch (b1 >> 4) {
  3133                 case 0:
  3134                 case 1:
  3135                 case 2:
  3136                 case 3:
  3137                 case 4:
  3138                 case 5:
  3139                 case 6:
  3140                 case 7:     // 1 byte format: 0xxxxxxx
  3141                     sbuf.append((char) b1);
  3142                     return 1;
  3143 
  3144                 case 12:
  3145                 case 13:    // 2 byte format: 110xxxxx 10xxxxxx
  3146                     if (utflen < 2) {
  3147                         throw new UTFDataFormatException();
  3148                     }
  3149                     b2 = readByte();
  3150                     if ((b2 & 0xC0) != 0x80) {
  3151                         throw new UTFDataFormatException();
  3152                     }
  3153                     sbuf.append((char) (((b1 & 0x1F) << 6) |
  3154                                         ((b2 & 0x3F) << 0)));
  3155                     return 2;
  3156 
  3157                 case 14:    // 3 byte format: 1110xxxx 10xxxxxx 10xxxxxx
  3158                     if (utflen < 3) {
  3159                         if (utflen == 2) {
  3160                             readByte();         // consume remaining byte
  3161                         }
  3162                         throw new UTFDataFormatException();
  3163                     }
  3164                     b2 = readByte();
  3165                     b3 = readByte();
  3166                     if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) {
  3167                         throw new UTFDataFormatException();
  3168                     }
  3169                     sbuf.append((char) (((b1 & 0x0F) << 12) |
  3170                                         ((b2 & 0x3F) << 6) |
  3171                                         ((b3 & 0x3F) << 0)));
  3172                     return 3;
  3173 
  3174                 default:   // 10xx xxxx, 1111 xxxx
  3175                     throw new UTFDataFormatException();
  3176             }
  3177         }
  3178     }
  3179 
  3180     /**
  3181      * Unsynchronized table which tracks wire handle to object mappings, as
  3182      * well as ClassNotFoundExceptions associated with deserialized objects.
  3183      * This class implements an exception-propagation algorithm for
  3184      * determining which objects should have ClassNotFoundExceptions associated
  3185      * with them, taking into account cycles and discontinuities (e.g., skipped
  3186      * fields) in the object graph.
  3187      *
  3188      * <p>General use of the table is as follows: during deserialization, a
  3189      * given object is first assigned a handle by calling the assign method.
  3190      * This method leaves the assigned handle in an "open" state, wherein
  3191      * dependencies on the exception status of other handles can be registered
  3192      * by calling the markDependency method, or an exception can be directly
  3193      * associated with the handle by calling markException.  When a handle is
  3194      * tagged with an exception, the HandleTable assumes responsibility for
  3195      * propagating the exception to any other objects which depend
  3196      * (transitively) on the exception-tagged object.
  3197      *
  3198      * <p>Once all exception information/dependencies for the handle have been
  3199      * registered, the handle should be "closed" by calling the finish method
  3200      * on it.  The act of finishing a handle allows the exception propagation
  3201      * algorithm to aggressively prune dependency links, lessening the
  3202      * performance/memory impact of exception tracking.
  3203      *
  3204      * <p>Note that the exception propagation algorithm used depends on handles
  3205      * being assigned/finished in LIFO order; however, for simplicity as well
  3206      * as memory conservation, it does not enforce this constraint.
  3207      */
  3208     // REMIND: add full description of exception propagation algorithm?
  3209     private static class HandleTable {
  3210 
  3211         /* status codes indicating whether object has associated exception */
  3212         private static final byte STATUS_OK = 1;
  3213         private static final byte STATUS_UNKNOWN = 2;
  3214         private static final byte STATUS_EXCEPTION = 3;
  3215 
  3216         /** array mapping handle -> object status */
  3217         byte[] status;
  3218         /** array mapping handle -> object/exception (depending on status) */
  3219         Object[] entries;
  3220         /** array mapping handle -> list of dependent handles (if any) */
  3221         HandleList[] deps;
  3222         /** lowest unresolved dependency */
  3223         int lowDep = -1;
  3224         /** number of handles in table */
  3225         int size = 0;
  3226 
  3227         /**
  3228          * Creates handle table with the given initial capacity.
  3229          */
  3230         HandleTable(int initialCapacity) {
  3231             status = new byte[initialCapacity];
  3232             entries = new Object[initialCapacity];
  3233             deps = new HandleList[initialCapacity];
  3234         }
  3235 
  3236         /**
  3237          * Assigns next available handle to given object, and returns assigned
  3238          * handle.  Once object has been completely deserialized (and all
  3239          * dependencies on other objects identified), the handle should be
  3240          * "closed" by passing it to finish().
  3241          */
  3242         int assign(Object obj) {
  3243             if (size >= entries.length) {
  3244                 grow();
  3245             }
  3246             status[size] = STATUS_UNKNOWN;
  3247             entries[size] = obj;
  3248             return size++;
  3249         }
  3250 
  3251         /**
  3252          * Registers a dependency (in exception status) of one handle on
  3253          * another.  The dependent handle must be "open" (i.e., assigned, but
  3254          * not finished yet).  No action is taken if either dependent or target
  3255          * handle is NULL_HANDLE.
  3256          */
  3257         void markDependency(int dependent, int target) {
  3258             if (dependent == NULL_HANDLE || target == NULL_HANDLE) {
  3259                 return;
  3260             }
  3261             switch (status[dependent]) {
  3262 
  3263                 case STATUS_UNKNOWN:
  3264                     switch (status[target]) {
  3265                         case STATUS_OK:
  3266                             // ignore dependencies on objs with no exception
  3267                             break;
  3268 
  3269                         case STATUS_EXCEPTION:
  3270                             // eagerly propagate exception
  3271                             markException(dependent,
  3272                                 (ClassNotFoundException) entries[target]);
  3273                             break;
  3274 
  3275                         case STATUS_UNKNOWN:
  3276                             // add to dependency list of target
  3277                             if (deps[target] == null) {
  3278                                 deps[target] = new HandleList();
  3279                             }
  3280                             deps[target].add(dependent);
  3281 
  3282                             // remember lowest unresolved target seen
  3283                             if (lowDep < 0 || lowDep > target) {
  3284                                 lowDep = target;
  3285                             }
  3286                             break;
  3287 
  3288                         default:
  3289                             throw new InternalError();
  3290                     }
  3291                     break;
  3292 
  3293                 case STATUS_EXCEPTION:
  3294                     break;
  3295 
  3296                 default:
  3297                     throw new InternalError();
  3298             }
  3299         }
  3300 
  3301         /**
  3302          * Associates a ClassNotFoundException (if one not already associated)
  3303          * with the currently active handle and propagates it to other
  3304          * referencing objects as appropriate.  The specified handle must be
  3305          * "open" (i.e., assigned, but not finished yet).
  3306          */
  3307         void markException(int handle, ClassNotFoundException ex) {
  3308             switch (status[handle]) {
  3309                 case STATUS_UNKNOWN:
  3310                     status[handle] = STATUS_EXCEPTION;
  3311                     entries[handle] = ex;
  3312 
  3313                     // propagate exception to dependents
  3314                     HandleList dlist = deps[handle];
  3315                     if (dlist != null) {
  3316                         int ndeps = dlist.size();
  3317                         for (int i = 0; i < ndeps; i++) {
  3318                             markException(dlist.get(i), ex);
  3319                         }
  3320                         deps[handle] = null;
  3321                     }
  3322                     break;
  3323 
  3324                 case STATUS_EXCEPTION:
  3325                     break;
  3326 
  3327                 default:
  3328                     throw new InternalError();
  3329             }
  3330         }
  3331 
  3332         /**
  3333          * Marks given handle as finished, meaning that no new dependencies
  3334          * will be marked for handle.  Calls to the assign and finish methods
  3335          * must occur in LIFO order.
  3336          */
  3337         void finish(int handle) {
  3338             int end;
  3339             if (lowDep < 0) {
  3340                 // no pending unknowns, only resolve current handle
  3341                 end = handle + 1;
  3342             } else if (lowDep >= handle) {
  3343                 // pending unknowns now clearable, resolve all upward handles
  3344                 end = size;
  3345                 lowDep = -1;
  3346             } else {
  3347                 // unresolved backrefs present, can't resolve anything yet
  3348                 return;
  3349             }
  3350 
  3351             // change STATUS_UNKNOWN -> STATUS_OK in selected span of handles
  3352             for (int i = handle; i < end; i++) {
  3353                 switch (status[i]) {
  3354                     case STATUS_UNKNOWN:
  3355                         status[i] = STATUS_OK;
  3356                         deps[i] = null;
  3357                         break;
  3358 
  3359                     case STATUS_OK:
  3360                     case STATUS_EXCEPTION:
  3361                         break;
  3362 
  3363                     default:
  3364                         throw new InternalError();
  3365                 }
  3366             }
  3367         }
  3368 
  3369         /**
  3370          * Assigns a new object to the given handle.  The object previously
  3371          * associated with the handle is forgotten.  This method has no effect
  3372          * if the given handle already has an exception associated with it.
  3373          * This method may be called at any time after the handle is assigned.
  3374          */
  3375         void setObject(int handle, Object obj) {
  3376             switch (status[handle]) {
  3377                 case STATUS_UNKNOWN:
  3378                 case STATUS_OK:
  3379                     entries[handle] = obj;
  3380                     break;
  3381 
  3382                 case STATUS_EXCEPTION:
  3383                     break;
  3384 
  3385                 default:
  3386                     throw new InternalError();
  3387             }
  3388         }
  3389 
  3390         /**
  3391          * Looks up and returns object associated with the given handle.
  3392          * Returns null if the given handle is NULL_HANDLE, or if it has an
  3393          * associated ClassNotFoundException.
  3394          */
  3395         Object lookupObject(int handle) {
  3396             return (handle != NULL_HANDLE &&
  3397                     status[handle] != STATUS_EXCEPTION) ?
  3398                 entries[handle] : null;
  3399         }
  3400 
  3401         /**
  3402          * Looks up and returns ClassNotFoundException associated with the
  3403          * given handle.  Returns null if the given handle is NULL_HANDLE, or
  3404          * if there is no ClassNotFoundException associated with the handle.
  3405          */
  3406         ClassNotFoundException lookupException(int handle) {
  3407             return (handle != NULL_HANDLE &&
  3408                     status[handle] == STATUS_EXCEPTION) ?
  3409                 (ClassNotFoundException) entries[handle] : null;
  3410         }
  3411 
  3412         /**
  3413          * Resets table to its initial state.
  3414          */
  3415         void clear() {
  3416             Arrays.fill(status, 0, size, (byte) 0);
  3417             Arrays.fill(entries, 0, size, null);
  3418             Arrays.fill(deps, 0, size, null);
  3419             lowDep = -1;
  3420             size = 0;
  3421         }
  3422 
  3423         /**
  3424          * Returns number of handles registered in table.
  3425          */
  3426         int size() {
  3427             return size;
  3428         }
  3429 
  3430         /**
  3431          * Expands capacity of internal arrays.
  3432          */
  3433         private void grow() {
  3434             int newCapacity = (entries.length << 1) + 1;
  3435 
  3436             byte[] newStatus = new byte[newCapacity];
  3437             Object[] newEntries = new Object[newCapacity];
  3438             HandleList[] newDeps = new HandleList[newCapacity];
  3439 
  3440             System.arraycopy(status, 0, newStatus, 0, size);
  3441             System.arraycopy(entries, 0, newEntries, 0, size);
  3442             System.arraycopy(deps, 0, newDeps, 0, size);
  3443 
  3444             status = newStatus;
  3445             entries = newEntries;
  3446             deps = newDeps;
  3447         }
  3448 
  3449         /**
  3450          * Simple growable list of (integer) handles.
  3451          */
  3452         private static class HandleList {
  3453             private int[] list = new int[4];
  3454             private int size = 0;
  3455 
  3456             public HandleList() {
  3457             }
  3458 
  3459             public void add(int handle) {
  3460                 if (size >= list.length) {
  3461                     int[] newList = new int[list.length << 1];
  3462                     System.arraycopy(list, 0, newList, 0, list.length);
  3463                     list = newList;
  3464                 }
  3465                 list[size++] = handle;
  3466             }
  3467 
  3468             public int get(int index) {
  3469                 if (index >= size) {
  3470                     throw new ArrayIndexOutOfBoundsException();
  3471                 }
  3472                 return list[index];
  3473             }
  3474 
  3475             public int size() {
  3476                 return size;
  3477             }
  3478         }
  3479     }
  3480 
  3481     /**
  3482      * Method for cloning arrays in case of using unsharing reading
  3483      */
  3484     private static Object cloneArray(Object array) {
  3485         if (array instanceof Object[]) {
  3486             return ((Object[]) array).clone();
  3487         } else if (array instanceof boolean[]) {
  3488             return ((boolean[]) array).clone();
  3489         } else if (array instanceof byte[]) {
  3490             return ((byte[]) array).clone();
  3491         } else if (array instanceof char[]) {
  3492             return ((char[]) array).clone();
  3493         } else if (array instanceof double[]) {
  3494             return ((double[]) array).clone();
  3495         } else if (array instanceof float[]) {
  3496             return ((float[]) array).clone();
  3497         } else if (array instanceof int[]) {
  3498             return ((int[]) array).clone();
  3499         } else if (array instanceof long[]) {
  3500             return ((long[]) array).clone();
  3501         } else if (array instanceof short[]) {
  3502             return ((short[]) array).clone();
  3503         } else {
  3504             throw new AssertionError();
  3505         }
  3506     }
  3507 
  3508 }