Home | History | Annotate | Download | only in io
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
      4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      5  *
      6  * This code is free software; you can redistribute it and/or modify it
      7  * under the terms of the GNU General Public License version 2 only, as
      8  * published by the Free Software Foundation.  Oracle designates this
      9  * particular file as subject to the "Classpath" exception as provided
     10  * by Oracle in the LICENSE file that accompanied this code.
     11  *
     12  * This code is distributed in the hope that it will be useful, but WITHOUT
     13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     15  * version 2 for more details (a copy is included in the LICENSE file that
     16  * accompanied this code).
     17  *
     18  * You should have received a copy of the GNU General Public License version
     19  * 2 along with this work; if not, write to the Free Software Foundation,
     20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     21  *
     22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     23  * or visit www.oracle.com if you need additional information or have any
     24  * questions.
     25  */
     26 
     27 package java.io;
     28 
     29 import java.io.ObjectStreamClass.WeakClassKey;
     30 import java.lang.ref.ReferenceQueue;
     31 import java.lang.reflect.Array;
     32 import java.lang.reflect.Modifier;
     33 import java.lang.reflect.Proxy;
     34 import java.security.AccessControlContext;
     35 import java.security.AccessController;
     36 import java.security.PrivilegedAction;
     37 import java.security.PrivilegedActionException;
     38 import java.security.PrivilegedExceptionAction;
     39 import java.util.Arrays;
     40 import java.util.HashMap;
     41 import java.util.concurrent.ConcurrentHashMap;
     42 import java.util.concurrent.ConcurrentMap;
     43 import java.util.concurrent.atomic.AtomicBoolean;
     44 import static java.io.ObjectStreamClass.processQueue;
     45 import sun.reflect.misc.ReflectUtil;
     46 import dalvik.system.VMStack;
     47 
     48 /**
     49  * An ObjectInputStream deserializes primitive data and objects previously
     50  * written using an ObjectOutputStream.
     51  *
     52  * <p>ObjectOutputStream and ObjectInputStream can provide an application with
     53  * persistent storage for graphs of objects when used with a FileOutputStream
     54  * and FileInputStream respectively.  ObjectInputStream is used to recover
     55  * those objects previously serialized. Other uses include passing objects
     56  * between hosts using a socket stream or for marshaling and unmarshaling
     57  * arguments and parameters in a remote communication system.
     58  *
     59  * <p>ObjectInputStream ensures that the types of all objects in the graph
     60  * created from the stream match the classes present in the Java Virtual
     61  * Machine.  Classes are loaded as required using the standard mechanisms.
     62  *
     63  * <p>Only objects that support the java.io.Serializable or
     64  * java.io.Externalizable interface can be read from streams.
     65  *
     66  * <p>The method <code>readObject</code> is used to read an object from the
     67  * stream.  Java's safe casting should be used to get the desired type.  In
     68  * Java, strings and arrays are objects and are treated as objects during
     69  * serialization. When read they need to be cast to the expected type.
     70  *
     71  * <p>Primitive data types can be read from the stream using the appropriate
     72  * method on DataInput.
     73  *
     74  * <p>The default deserialization mechanism for objects restores the contents
     75  * of each field to the value and type it had when it was written.  Fields
     76  * declared as transient or static are ignored by the deserialization process.
     77  * References to other objects cause those objects to be read from the stream
     78  * as necessary.  Graphs of objects are restored correctly using a reference
     79  * sharing mechanism.  New objects are always allocated when deserializing,
     80  * which prevents existing objects from being overwritten.
     81  *
     82  * <p>Reading an object is analogous to running the constructors of a new
     83  * object.  Memory is allocated for the object and initialized to zero (NULL).
     84  * No-arg constructors are invoked for the non-serializable classes and then
     85  * the fields of the serializable classes are restored from the stream starting
     86  * with the serializable class closest to java.lang.object and finishing with
     87  * the object's most specific class.
     88  *
     89  * <p>For example to read from a stream as written by the example in
     90  * ObjectOutputStream:
     91  * <br>
     92  * <pre>
     93  *      FileInputStream fis = new FileInputStream("t.tmp");
     94  *      ObjectInputStream ois = new ObjectInputStream(fis);
     95  *
     96  *      int i = ois.readInt();
     97  *      String today = (String) ois.readObject();
     98  *      Date date = (Date) ois.readObject();
     99  *
    100  *      ois.close();
    101  * </pre>
    102  *
    103  * <p>Classes control how they are serialized by implementing either the
    104  * java.io.Serializable or java.io.Externalizable interfaces.
    105  *
    106  * <p>Implementing the Serializable interface allows object serialization to
    107  * save and restore the entire state of the object and it allows classes to
    108  * evolve between the time the stream is written and the time it is read.  It
    109  * automatically traverses references between objects, saving and restoring
    110  * entire graphs.
    111  *
    112  * <p>Serializable classes that require special handling during the
    113  * serialization and deserialization process should implement the following
    114  * methods:<p>
    115  *
    116  * <pre>
    117  * private void writeObject(java.io.ObjectOutputStream stream)
    118  *     throws IOException;
    119  * private void readObject(java.io.ObjectInputStream stream)
    120  *     throws IOException, ClassNotFoundException;
    121  * private void readObjectNoData()
    122  *     throws ObjectStreamException;
    123  * </pre>
    124  *
    125  * <p>The readObject method is responsible for reading and restoring the state
    126  * of the object for its particular class using data written to the stream by
    127  * the corresponding writeObject method.  The method does not need to concern
    128  * itself with the state belonging to its superclasses or subclasses.  State is
    129  * restored by reading data from the ObjectInputStream for the individual
    130  * fields and making assignments to the appropriate fields of the object.
    131  * Reading primitive data types is supported by DataInput.
    132  *
    133  * <p>Any attempt to read object data which exceeds the boundaries of the
    134  * custom data written by the corresponding writeObject method will cause an
    135  * OptionalDataException to be thrown with an eof field value of true.
    136  * Non-object reads which exceed the end of the allotted data will reflect the
    137  * end of data in the same way that they would indicate the end of the stream:
    138  * bytewise reads will return -1 as the byte read or number of bytes read, and
    139  * primitive reads will throw EOFExceptions.  If there is no corresponding
    140  * writeObject method, then the end of default serialized data marks the end of
    141  * the allotted data.
    142  *
    143  * <p>Primitive and object read calls issued from within a readExternal method
    144  * behave in the same manner--if the stream is already positioned at the end of
    145  * data written by the corresponding writeExternal method, object reads will
    146  * throw OptionalDataExceptions with eof set to true, bytewise reads will
    147  * return -1, and primitive reads will throw EOFExceptions.  Note that this
    148  * behavior does not hold for streams written with the old
    149  * <code>ObjectStreamConstants.PROTOCOL_VERSION_1</code> protocol, in which the
    150  * end of data written by writeExternal methods is not demarcated, and hence
    151  * cannot be detected.
    152  *
    153  * <p>The readObjectNoData method is responsible for initializing the state of
    154  * the object for its particular class in the event that the serialization
    155  * stream does not list the given class as a superclass of the object being
    156  * deserialized.  This may occur in cases where the receiving party uses a
    157  * different version of the deserialized instance's class than the sending
    158  * party, and the receiver's version extends classes that are not extended by
    159  * the sender's version.  This may also occur if the serialization stream has
    160  * been tampered; hence, readObjectNoData is useful for initializing
    161  * deserialized objects properly despite a "hostile" or incomplete source
    162  * stream.
    163  *
    164  * <p>Serialization does not read or assign values to the fields of any object
    165  * that does not implement the java.io.Serializable interface.  Subclasses of
    166  * Objects that are not serializable can be serializable. In this case the
    167  * non-serializable class must have a no-arg constructor to allow its fields to
    168  * be initialized.  In this case it is the responsibility of the subclass to
    169  * save and restore the state of the non-serializable class. It is frequently
    170  * the case that the fields of that class are accessible (public, package, or
    171  * protected) or that there are get and set methods that can be used to restore
    172  * the state.
    173  *
    174  * <p>Any exception that occurs while deserializing an object will be caught by
    175  * the ObjectInputStream and abort the reading process.
    176  *
    177  * <p>Implementing the Externalizable interface allows the object to assume
    178  * complete control over the contents and format of the object's serialized
    179  * form.  The methods of the Externalizable interface, writeExternal and
    180  * readExternal, are called to save and restore the objects state.  When
    181  * implemented by a class they can write and read their own state using all of
    182  * the methods of ObjectOutput and ObjectInput.  It is the responsibility of
    183  * the objects to handle any versioning that occurs.
    184  *
    185  * <p>Enum constants are deserialized differently than ordinary serializable or
    186  * externalizable objects.  The serialized form of an enum constant consists
    187  * solely of its name; field values of the constant are not transmitted.  To
    188  * deserialize an enum constant, ObjectInputStream reads the constant name from
    189  * the stream; the deserialized constant is then obtained by calling the static
    190  * method <code>Enum.valueOf(Class, String)</code> with the enum constant's
    191  * base type and the received constant name as arguments.  Like other
    192  * serializable or externalizable objects, enum constants can function as the
    193  * targets of back references appearing subsequently in the serialization
    194  * stream.  The process by which enum constants are deserialized cannot be
    195  * customized: any class-specific readObject, readObjectNoData, and readResolve
    196  * methods defined by enum types are ignored during deserialization.
    197  * Similarly, any serialPersistentFields or serialVersionUID field declarations
    198  * are also ignored--all enum types have a fixed serialVersionUID of 0L.
    199  *
    200  * @author      Mike Warres
    201  * @author      Roger Riggs
    202  * @see java.io.DataInput
    203  * @see java.io.ObjectOutputStream
    204  * @see java.io.Serializable
    205  * @see <a href="{@docRoot}openjdk-redirect.html?v=8&path=/platform/serialization/spec/input.html"> Object Serialization Specification, Section 3, Object Input Classes</a>
    206  * @since   JDK1.1
    207  */
    208 public class ObjectInputStream
    209     extends InputStream implements ObjectInput, ObjectStreamConstants
    210 {
    211 
    212     /** handle value representing null */
    213     private static final int NULL_HANDLE = -1;
    214 
    215     /** marker for unshared objects in internal handle table */
    216     private static final Object unsharedMarker = new Object();
    217 
    218     /** table mapping primitive type names to corresponding class objects */
    219     private static final HashMap<String, Class<?>> primClasses
    220         = new HashMap<>(8, 1.0F);
    221     static {
    222         primClasses.put("boolean", boolean.class);
    223         primClasses.put("byte", byte.class);
    224         primClasses.put("char", char.class);
    225         primClasses.put("short", short.class);
    226         primClasses.put("int", int.class);
    227         primClasses.put("long", long.class);
    228         primClasses.put("float", float.class);
    229         primClasses.put("double", double.class);
    230         primClasses.put("void", void.class);
    231     }
    232 
    233     private static class Caches {
    234         /** cache of subclass security audit results */
    235         static final ConcurrentMap<WeakClassKey,Boolean> subclassAudits =
    236             new ConcurrentHashMap<>();
    237 
    238         /** queue for WeakReferences to audited subclasses */
    239         static final ReferenceQueue<Class<?>> subclassAuditsQueue =
    240             new ReferenceQueue<>();
    241     }
    242 
    243     /** filter stream for handling block data conversion */
    244     private final BlockDataInputStream bin;
    245     /** validation callback list */
    246     private final ValidationList vlist;
    247     /** recursion depth */
    248     private int depth;
    249     /** whether stream is closed */
    250     private boolean closed;
    251 
    252     /** wire handle -> obj/exception map */
    253     private final HandleTable handles;
    254     /** scratch field for passing handle values up/down call stack */
    255     private int passHandle = NULL_HANDLE;
    256     /** flag set when at end of field value block with no TC_ENDBLOCKDATA */
    257     private boolean defaultDataEnd = false;
    258 
    259     /** buffer for reading primitive field values */
    260     private byte[] primVals;
    261 
    262     /** if true, invoke readObjectOverride() instead of readObject() */
    263     private final boolean enableOverride;
    264     /** if true, invoke resolveObject() */
    265     private boolean enableResolve;
    266 
    267     /**
    268      * Context during upcalls to class-defined readObject methods; holds
    269      * object currently being deserialized and descriptor for current class.
    270      * Null when not during readObject upcall.
    271      */
    272     private SerialCallbackContext curContext;
    273 
    274     /**
    275      * Creates an ObjectInputStream that reads from the specified InputStream.
    276      * A serialization stream header is read from the stream and verified.
    277      * This constructor will block until the corresponding ObjectOutputStream
    278      * has written and flushed the header.
    279      *
    280      * <p>If a security manager is installed, this constructor will check for
    281      * the "enableSubclassImplementation" SerializablePermission when invoked
    282      * directly or indirectly by the constructor of a subclass which overrides
    283      * the ObjectInputStream.readFields or ObjectInputStream.readUnshared
    284      * methods.
    285      *
    286      * @param   in input stream to read from
    287      * @throws  StreamCorruptedException if the stream header is incorrect
    288      * @throws  IOException if an I/O error occurs while reading stream header
    289      * @throws  SecurityException if untrusted subclass illegally overrides
    290      *          security-sensitive methods
    291      * @throws  NullPointerException if <code>in</code> is <code>null</code>
    292      * @see     ObjectInputStream#ObjectInputStream()
    293      * @see     ObjectInputStream#readFields()
    294      * @see     ObjectOutputStream#ObjectOutputStream(OutputStream)
    295      */
    296     public ObjectInputStream(InputStream in) throws IOException {
    297         verifySubclass();
    298         bin = new BlockDataInputStream(in);
    299         handles = new HandleTable(10);
    300         vlist = new ValidationList();
    301         enableOverride = false;
    302         readStreamHeader();
    303         bin.setBlockDataMode(true);
    304     }
    305 
    306     /**
    307      * Provide a way for subclasses that are completely reimplementing
    308      * ObjectInputStream to not have to allocate private data just used by this
    309      * implementation of ObjectInputStream.
    310      *
    311      * <p>If there is a security manager installed, this method first calls the
    312      * security manager's <code>checkPermission</code> method with the
    313      * <code>SerializablePermission("enableSubclassImplementation")</code>
    314      * permission to ensure it's ok to enable subclassing.
    315      *
    316      * @throws  SecurityException if a security manager exists and its
    317      *          <code>checkPermission</code> method denies enabling
    318      *          subclassing.
    319      * @see SecurityManager#checkPermission
    320      * @see java.io.SerializablePermission
    321      */
    322     protected ObjectInputStream() throws IOException, SecurityException {
    323         SecurityManager sm = System.getSecurityManager();
    324         if (sm != null) {
    325             sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
    326         }
    327         bin = null;
    328         handles = null;
    329         vlist = null;
    330         enableOverride = true;
    331     }
    332 
    333     /**
    334      * Read an object from the ObjectInputStream.  The class of the object, the
    335      * signature of the class, and the values of the non-transient and
    336      * non-static fields of the class and all of its supertypes are read.
    337      * Default deserializing for a class can be overriden using the writeObject
    338      * and readObject methods.  Objects referenced by this object are read
    339      * transitively so that a complete equivalent graph of objects is
    340      * reconstructed by readObject.
    341      *
    342      * <p>The root object is completely restored when all of its fields and the
    343      * objects it references are completely restored.  At this point the object
    344      * validation callbacks are executed in order based on their registered
    345      * priorities. The callbacks are registered by objects (in the readObject
    346      * special methods) as they are individually restored.
    347      *
    348      * <p>Exceptions are thrown for problems with the InputStream and for
    349      * classes that should not be deserialized.  All exceptions are fatal to
    350      * the InputStream and leave it in an indeterminate state; it is up to the
    351      * caller to ignore or recover the stream state.
    352      *
    353      * @throws  ClassNotFoundException Class of a serialized object cannot be
    354      *          found.
    355      * @throws  InvalidClassException Something is wrong with a class used by
    356      *          serialization.
    357      * @throws  StreamCorruptedException Control information in the
    358      *          stream is inconsistent.
    359      * @throws  OptionalDataException Primitive data was found in the
    360      *          stream instead of objects.
    361      * @throws  IOException Any of the usual Input/Output related exceptions.
    362      */
    363     public final Object readObject()
    364         throws IOException, ClassNotFoundException
    365     {
    366         if (enableOverride) {
    367             return readObjectOverride();
    368         }
    369 
    370         // if nested read, passHandle contains handle of enclosing object
    371         int outerHandle = passHandle;
    372         try {
    373             Object obj = readObject0(false);
    374             handles.markDependency(outerHandle, passHandle);
    375             ClassNotFoundException ex = handles.lookupException(passHandle);
    376             if (ex != null) {
    377                 throw ex;
    378             }
    379             if (depth == 0) {
    380                 vlist.doCallbacks();
    381             }
    382             return obj;
    383         } finally {
    384             passHandle = outerHandle;
    385             if (closed && depth == 0) {
    386                 clear();
    387             }
    388         }
    389     }
    390 
    391     /**
    392      * This method is called by trusted subclasses of ObjectOutputStream that
    393      * constructed ObjectOutputStream using the protected no-arg constructor.
    394      * The subclass is expected to provide an override method with the modifier
    395      * "final".
    396      *
    397      * @return  the Object read from the stream.
    398      * @throws  ClassNotFoundException Class definition of a serialized object
    399      *          cannot be found.
    400      * @throws  OptionalDataException Primitive data was found in the stream
    401      *          instead of objects.
    402      * @throws  IOException if I/O errors occurred while reading from the
    403      *          underlying stream
    404      * @see #ObjectInputStream()
    405      * @see #readObject()
    406      * @since 1.2
    407      */
    408     protected Object readObjectOverride()
    409         throws IOException, ClassNotFoundException
    410     {
    411         return null;
    412     }
    413 
    414     /**
    415      * Reads an "unshared" object from the ObjectInputStream.  This method is
    416      * identical to readObject, except that it prevents subsequent calls to
    417      * readObject and readUnshared from returning additional references to the
    418      * deserialized instance obtained via this call.  Specifically:
    419      * <ul>
    420      *   <li>If readUnshared is called to deserialize a back-reference (the
    421      *       stream representation of an object which has been written
    422      *       previously to the stream), an ObjectStreamException will be
    423      *       thrown.
    424      *
    425      *   <li>If readUnshared returns successfully, then any subsequent attempts
    426      *       to deserialize back-references to the stream handle deserialized
    427      *       by readUnshared will cause an ObjectStreamException to be thrown.
    428      * </ul>
    429      * Deserializing an object via readUnshared invalidates the stream handle
    430      * associated with the returned object.  Note that this in itself does not
    431      * always guarantee that the reference returned by readUnshared is unique;
    432      * the deserialized object may define a readResolve method which returns an
    433      * object visible to other parties, or readUnshared may return a Class
    434      * object or enum constant obtainable elsewhere in the stream or through
    435      * external means. If the deserialized object defines a readResolve method
    436      * and the invocation of that method returns an array, then readUnshared
    437      * returns a shallow clone of that array; this guarantees that the returned
    438      * array object is unique and cannot be obtained a second time from an
    439      * invocation of readObject or readUnshared on the ObjectInputStream,
    440      * even if the underlying data stream has been manipulated.
    441      *
    442      * <p>ObjectInputStream subclasses which override this method can only be
    443      * constructed in security contexts possessing the
    444      * "enableSubclassImplementation" SerializablePermission; any attempt to
    445      * instantiate such a subclass without this permission will cause a
    446      * SecurityException to be thrown.
    447      *
    448      * @return  reference to deserialized object
    449      * @throws  ClassNotFoundException if class of an object to deserialize
    450      *          cannot be found
    451      * @throws  StreamCorruptedException if control information in the stream
    452      *          is inconsistent
    453      * @throws  ObjectStreamException if object to deserialize has already
    454      *          appeared in stream
    455      * @throws  OptionalDataException if primitive data is next in stream
    456      * @throws  IOException if an I/O error occurs during deserialization
    457      * @since   1.4
    458      */
    459     public Object readUnshared() throws IOException, ClassNotFoundException {
    460         // if nested read, passHandle contains handle of enclosing object
    461         int outerHandle = passHandle;
    462         try {
    463             Object obj = readObject0(true);
    464             handles.markDependency(outerHandle, passHandle);
    465             ClassNotFoundException ex = handles.lookupException(passHandle);
    466             if (ex != null) {
    467                 throw ex;
    468             }
    469             if (depth == 0) {
    470                 vlist.doCallbacks();
    471             }
    472             return obj;
    473         } finally {
    474             passHandle = outerHandle;
    475             if (closed && depth == 0) {
    476                 clear();
    477             }
    478         }
    479     }
    480 
    481     /**
    482      * Read the non-static and non-transient fields of the current class from
    483      * this stream.  This may only be called from the readObject method of the
    484      * class being deserialized. It will throw the NotActiveException if it is
    485      * called otherwise.
    486      *
    487      * @throws  ClassNotFoundException if the class of a serialized object
    488      *          could not be found.
    489      * @throws  IOException if an I/O error occurs.
    490      * @throws  NotActiveException if the stream is not currently reading
    491      *          objects.
    492      */
    493     public void defaultReadObject()
    494         throws IOException, ClassNotFoundException
    495     {
    496         if (curContext == null) {
    497             throw new NotActiveException("not in call to readObject");
    498         }
    499         Object curObj = curContext.getObj();
    500         ObjectStreamClass curDesc = curContext.getDesc();
    501         bin.setBlockDataMode(false);
    502         defaultReadFields(curObj, curDesc);
    503         bin.setBlockDataMode(true);
    504         if (!curDesc.hasWriteObjectData()) {
    505             /*
    506              * Fix for 4360508: since stream does not contain terminating
    507              * TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere
    508              * knows to simulate end-of-custom-data behavior.
    509              */
    510             defaultDataEnd = true;
    511         }
    512         ClassNotFoundException ex = handles.lookupException(passHandle);
    513         if (ex != null) {
    514             throw ex;
    515         }
    516     }
    517 
    518     /**
    519      * Reads the persistent fields from the stream and makes them available by
    520      * name.
    521      *
    522      * @return  the <code>GetField</code> object representing the persistent
    523      *          fields of the object being deserialized
    524      * @throws  ClassNotFoundException if the class of a serialized object
    525      *          could not be found.
    526      * @throws  IOException if an I/O error occurs.
    527      * @throws  NotActiveException if the stream is not currently reading
    528      *          objects.
    529      * @since 1.2
    530      */
    531     public ObjectInputStream.GetField readFields()
    532         throws IOException, ClassNotFoundException
    533     {
    534         if (curContext == null) {
    535             throw new NotActiveException("not in call to readObject");
    536         }
    537         Object curObj = curContext.getObj();
    538         ObjectStreamClass curDesc = curContext.getDesc();
    539         bin.setBlockDataMode(false);
    540         GetFieldImpl getField = new GetFieldImpl(curDesc);
    541         getField.readFields();
    542         bin.setBlockDataMode(true);
    543         if (!curDesc.hasWriteObjectData()) {
    544             /*
    545              * Fix for 4360508: since stream does not contain terminating
    546              * TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere
    547              * knows to simulate end-of-custom-data behavior.
    548              */
    549             defaultDataEnd = true;
    550         }
    551 
    552         return getField;
    553     }
    554 
    555     /**
    556      * Register an object to be validated before the graph is returned.  While
    557      * similar to resolveObject these validations are called after the entire
    558      * graph has been reconstituted.  Typically, a readObject method will
    559      * register the object with the stream so that when all of the objects are
    560      * restored a final set of validations can be performed.
    561      *
    562      * @param   obj the object to receive the validation callback.
    563      * @param   prio controls the order of callbacks;zero is a good default.
    564      *          Use higher numbers to be called back earlier, lower numbers for
    565      *          later callbacks. Within a priority, callbacks are processed in
    566      *          no particular order.
    567      * @throws  NotActiveException The stream is not currently reading objects
    568      *          so it is invalid to register a callback.
    569      * @throws  InvalidObjectException The validation object is null.
    570      */
    571     public void registerValidation(ObjectInputValidation obj, int prio)
    572         throws NotActiveException, InvalidObjectException
    573     {
    574         if (depth == 0) {
    575             throw new NotActiveException("stream inactive");
    576         }
    577         vlist.register(obj, prio);
    578     }
    579 
    580     /**
    581      * Load the local class equivalent of the specified stream class
    582      * description.  Subclasses may implement this method to allow classes to
    583      * be fetched from an alternate source.
    584      *
    585      * <p>The corresponding method in <code>ObjectOutputStream</code> is
    586      * <code>annotateClass</code>.  This method will be invoked only once for
    587      * each unique class in the stream.  This method can be implemented by
    588      * subclasses to use an alternate loading mechanism but must return a
    589      * <code>Class</code> object. Once returned, if the class is not an array
    590      * class, its serialVersionUID is compared to the serialVersionUID of the
    591      * serialized class, and if there is a mismatch, the deserialization fails
    592      * and an {@link InvalidClassException} is thrown.
    593      *
    594      * <p>The default implementation of this method in
    595      * <code>ObjectInputStream</code> returns the result of calling
    596      * <pre>
    597      *     Class.forName(desc.getName(), false, loader)
    598      * </pre>
    599      * where <code>loader</code> is determined as follows: if there is a
    600      * method on the current thread's stack whose declaring class was
    601      * defined by a user-defined class loader (and was not a generated to
    602      * implement reflective invocations), then <code>loader</code> is class
    603      * loader corresponding to the closest such method to the currently
    604      * executing frame; otherwise, <code>loader</code> is
    605      * <code>null</code>. If this call results in a
    606      * <code>ClassNotFoundException</code> and the name of the passed
    607      * <code>ObjectStreamClass</code> instance is the Java language keyword
    608      * for a primitive type or void, then the <code>Class</code> object
    609      * representing that primitive type or void will be returned
    610      * (e.g., an <code>ObjectStreamClass</code> with the name
    611      * <code>"int"</code> will be resolved to <code>Integer.TYPE</code>).
    612      * Otherwise, the <code>ClassNotFoundException</code> will be thrown to
    613      * the caller of this method.
    614      *
    615      * @param   desc an instance of class <code>ObjectStreamClass</code>
    616      * @return  a <code>Class</code> object corresponding to <code>desc</code>
    617      * @throws  IOException any of the usual Input/Output exceptions.
    618      * @throws  ClassNotFoundException if class of a serialized object cannot
    619      *          be found.
    620      */
    621     protected Class<?> resolveClass(ObjectStreamClass desc)
    622         throws IOException, ClassNotFoundException
    623     {
    624         String name = desc.getName();
    625         try {
    626             return Class.forName(name, false, latestUserDefinedLoader());
    627         } catch (ClassNotFoundException ex) {
    628             Class<?> cl = primClasses.get(name);
    629             if (cl != null) {
    630                 return cl;
    631             } else {
    632                 throw ex;
    633             }
    634         }
    635     }
    636 
    637     /**
    638      * Returns a proxy class that implements the interfaces named in a proxy
    639      * class descriptor; subclasses may implement this method to read custom
    640      * data from the stream along with the descriptors for dynamic proxy
    641      * classes, allowing them to use an alternate loading mechanism for the
    642      * interfaces and the proxy class.
    643      *
    644      * <p>This method is called exactly once for each unique proxy class
    645      * descriptor in the stream.
    646      *
    647      * <p>The corresponding method in <code>ObjectOutputStream</code> is
    648      * <code>annotateProxyClass</code>.  For a given subclass of
    649      * <code>ObjectInputStream</code> that overrides this method, the
    650      * <code>annotateProxyClass</code> method in the corresponding subclass of
    651      * <code>ObjectOutputStream</code> must write any data or objects read by
    652      * this method.
    653      *
    654      * <p>The default implementation of this method in
    655      * <code>ObjectInputStream</code> returns the result of calling
    656      * <code>Proxy.getProxyClass</code> with the list of <code>Class</code>
    657      * objects for the interfaces that are named in the <code>interfaces</code>
    658      * parameter.  The <code>Class</code> object for each interface name
    659      * <code>i</code> is the value returned by calling
    660      * <pre>
    661      *     Class.forName(i, false, loader)
    662      * </pre>
    663      * where <code>loader</code> is that of the first non-<code>null</code>
    664      * class loader up the execution stack, or <code>null</code> if no
    665      * non-<code>null</code> class loaders are on the stack (the same class
    666      * loader choice used by the <code>resolveClass</code> method).  Unless any
    667      * of the resolved interfaces are non-public, this same value of
    668      * <code>loader</code> is also the class loader passed to
    669      * <code>Proxy.getProxyClass</code>; if non-public interfaces are present,
    670      * their class loader is passed instead (if more than one non-public
    671      * interface class loader is encountered, an
    672      * <code>IllegalAccessError</code> is thrown).
    673      * If <code>Proxy.getProxyClass</code> throws an
    674      * <code>IllegalArgumentException</code>, <code>resolveProxyClass</code>
    675      * will throw a <code>ClassNotFoundException</code> containing the
    676      * <code>IllegalArgumentException</code>.
    677      *
    678      * @param interfaces the list of interface names that were
    679      *                deserialized in the proxy class descriptor
    680      * @return  a proxy class for the specified interfaces
    681      * @throws        IOException any exception thrown by the underlying
    682      *                <code>InputStream</code>
    683      * @throws        ClassNotFoundException if the proxy class or any of the
    684      *                named interfaces could not be found
    685      * @see ObjectOutputStream#annotateProxyClass(Class)
    686      * @since 1.3
    687      */
    688     protected Class<?> resolveProxyClass(String[] interfaces)
    689         throws IOException, ClassNotFoundException
    690     {
    691         ClassLoader latestLoader = latestUserDefinedLoader();
    692         ClassLoader nonPublicLoader = null;
    693         boolean hasNonPublicInterface = false;
    694 
    695         // define proxy in class loader of non-public interface(s), if any
    696         Class[] classObjs = new Class[interfaces.length];
    697         for (int i = 0; i < interfaces.length; i++) {
    698             Class cl = Class.forName(interfaces[i], false, latestLoader);
    699             if ((cl.getModifiers() & Modifier.PUBLIC) == 0) {
    700                 if (hasNonPublicInterface) {
    701                     if (nonPublicLoader != cl.getClassLoader()) {
    702                         throw new IllegalAccessError(
    703                             "conflicting non-public interface class loaders");
    704                     }
    705                 } else {
    706                     nonPublicLoader = cl.getClassLoader();
    707                     hasNonPublicInterface = true;
    708                 }
    709             }
    710             classObjs[i] = cl;
    711         }
    712         try {
    713             return Proxy.getProxyClass(
    714                 hasNonPublicInterface ? nonPublicLoader : latestLoader,
    715                 classObjs);
    716         } catch (IllegalArgumentException e) {
    717             throw new ClassNotFoundException(null, e);
    718         }
    719     }
    720 
    721     /**
    722      * This method will allow trusted subclasses of ObjectInputStream to
    723      * substitute one object for another during deserialization. Replacing
    724      * objects is disabled until enableResolveObject is called. The
    725      * enableResolveObject method checks that the stream requesting to resolve
    726      * object can be trusted. Every reference to serializable objects is passed
    727      * to resolveObject.  To insure that the private state of objects is not
    728      * unintentionally exposed only trusted streams may use resolveObject.
    729      *
    730      * <p>This method is called after an object has been read but before it is
    731      * returned from readObject.  The default resolveObject method just returns
    732      * the same object.
    733      *
    734      * <p>When a subclass is replacing objects it must insure that the
    735      * substituted object is compatible with every field where the reference
    736      * will be stored.  Objects whose type is not a subclass of the type of the
    737      * field or array element abort the serialization by raising an exception
    738      * and the object is not be stored.
    739      *
    740      * <p>This method is called only once when each object is first
    741      * encountered.  All subsequent references to the object will be redirected
    742      * to the new object.
    743      *
    744      * @param   obj object to be substituted
    745      * @return  the substituted object
    746      * @throws  IOException Any of the usual Input/Output exceptions.
    747      */
    748     protected Object resolveObject(Object obj) throws IOException {
    749         return obj;
    750     }
    751 
    752     /**
    753      * Enable the stream to allow objects read from the stream to be replaced.
    754      * When enabled, the resolveObject method is called for every object being
    755      * deserialized.
    756      *
    757      * <p>If <i>enable</i> is true, and there is a security manager installed,
    758      * this method first calls the security manager's
    759      * <code>checkPermission</code> method with the
    760      * <code>SerializablePermission("enableSubstitution")</code> permission to
    761      * ensure it's ok to enable the stream to allow objects read from the
    762      * stream to be replaced.
    763      *
    764      * @param   enable true for enabling use of <code>resolveObject</code> for
    765      *          every object being deserialized
    766      * @return  the previous setting before this method was invoked
    767      * @throws  SecurityException if a security manager exists and its
    768      *          <code>checkPermission</code> method denies enabling the stream
    769      *          to allow objects read from the stream to be replaced.
    770      * @see SecurityManager#checkPermission
    771      * @see java.io.SerializablePermission
    772      */
    773     protected boolean enableResolveObject(boolean enable)
    774         throws SecurityException
    775     {
    776         if (enable == enableResolve) {
    777             return enable;
    778         }
    779         if (enable) {
    780             SecurityManager sm = System.getSecurityManager();
    781             if (sm != null) {
    782                 sm.checkPermission(SUBSTITUTION_PERMISSION);
    783             }
    784         }
    785         enableResolve = enable;
    786         return !enableResolve;
    787     }
    788 
    789     /**
    790      * The readStreamHeader method is provided to allow subclasses to read and
    791      * verify their own stream headers. It reads and verifies the magic number
    792      * and version number.
    793      *
    794      * @throws  IOException if there are I/O errors while reading from the
    795      *          underlying <code>InputStream</code>
    796      * @throws  StreamCorruptedException if control information in the stream
    797      *          is inconsistent
    798      */
    799     protected void readStreamHeader()
    800         throws IOException, StreamCorruptedException
    801     {
    802         short s0 = bin.readShort();
    803         short s1 = bin.readShort();
    804         if (s0 != STREAM_MAGIC || s1 != STREAM_VERSION) {
    805             throw new StreamCorruptedException(
    806                 String.format("invalid stream header: %04X%04X", s0, s1));
    807         }
    808     }
    809 
    810     /**
    811      * Read a class descriptor from the serialization stream.  This method is
    812      * called when the ObjectInputStream expects a class descriptor as the next
    813      * item in the serialization stream.  Subclasses of ObjectInputStream may
    814      * override this method to read in class descriptors that have been written
    815      * in non-standard formats (by subclasses of ObjectOutputStream which have
    816      * overridden the <code>writeClassDescriptor</code> method).  By default,
    817      * this method reads class descriptors according to the format defined in
    818      * the Object Serialization specification.
    819      *
    820      * @return  the class descriptor read
    821      * @throws  IOException If an I/O error has occurred.
    822      * @throws  ClassNotFoundException If the Class of a serialized object used
    823      *          in the class descriptor representation cannot be found
    824      * @see java.io.ObjectOutputStream#writeClassDescriptor(java.io.ObjectStreamClass)
    825      * @since 1.3
    826      */
    827     protected ObjectStreamClass readClassDescriptor()
    828         throws IOException, ClassNotFoundException
    829     {
    830         ObjectStreamClass desc = new ObjectStreamClass();
    831         desc.readNonProxy(this);
    832         return desc;
    833     }
    834 
    835     /**
    836      * Reads a byte of data. This method will block if no input is available.
    837      *
    838      * @return  the byte read, or -1 if the end of the stream is reached.
    839      * @throws  IOException If an I/O error has occurred.
    840      */
    841     public int read() throws IOException {
    842         return bin.read();
    843     }
    844 
    845     /**
    846      * Reads into an array of bytes.  This method will block until some input
    847      * is available. Consider using java.io.DataInputStream.readFully to read
    848      * exactly 'length' bytes.
    849      *
    850      * @param   buf the buffer into which the data is read
    851      * @param   off the start offset of the data
    852      * @param   len the maximum number of bytes read
    853      * @return  the actual number of bytes read, -1 is returned when the end of
    854      *          the stream is reached.
    855      * @throws  IOException If an I/O error has occurred.
    856      * @see java.io.DataInputStream#readFully(byte[],int,int)
    857      */
    858     public int read(byte[] buf, int off, int len) throws IOException {
    859         if (buf == null) {
    860             throw new NullPointerException();
    861         }
    862         int endoff = off + len;
    863         if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) {
    864             throw new IndexOutOfBoundsException();
    865         }
    866         return bin.read(buf, off, len, false);
    867     }
    868 
    869     /**
    870      * Returns the number of bytes that can be read without blocking.
    871      *
    872      * @return  the number of available bytes.
    873      * @throws  IOException if there are I/O errors while reading from the
    874      *          underlying <code>InputStream</code>
    875      */
    876     public int available() throws IOException {
    877         return bin.available();
    878     }
    879 
    880     /**
    881      * Closes the input stream. Must be called to release any resources
    882      * associated with the stream.
    883      *
    884      * @throws  IOException If an I/O error has occurred.
    885      */
    886     public void close() throws IOException {
    887         /*
    888          * Even if stream already closed, propagate redundant close to
    889          * underlying stream to stay consistent with previous implementations.
    890          */
    891         closed = true;
    892         if (depth == 0) {
    893             clear();
    894         }
    895         bin.close();
    896     }
    897 
    898     /**
    899      * Reads in a boolean.
    900      *
    901      * @return  the boolean read.
    902      * @throws  EOFException If end of file is reached.
    903      * @throws  IOException If other I/O error has occurred.
    904      */
    905     public boolean readBoolean() throws IOException {
    906         return bin.readBoolean();
    907     }
    908 
    909     /**
    910      * Reads an 8 bit byte.
    911      *
    912      * @return  the 8 bit byte read.
    913      * @throws  EOFException If end of file is reached.
    914      * @throws  IOException If other I/O error has occurred.
    915      */
    916     public byte readByte() throws IOException  {
    917         return bin.readByte();
    918     }
    919 
    920     /**
    921      * Reads an unsigned 8 bit byte.
    922      *
    923      * @return  the 8 bit byte read.
    924      * @throws  EOFException If end of file is reached.
    925      * @throws  IOException If other I/O error has occurred.
    926      */
    927     public int readUnsignedByte()  throws IOException {
    928         return bin.readUnsignedByte();
    929     }
    930 
    931     /**
    932      * Reads a 16 bit char.
    933      *
    934      * @return  the 16 bit char read.
    935      * @throws  EOFException If end of file is reached.
    936      * @throws  IOException If other I/O error has occurred.
    937      */
    938     public char readChar()  throws IOException {
    939         return bin.readChar();
    940     }
    941 
    942     /**
    943      * Reads a 16 bit short.
    944      *
    945      * @return  the 16 bit short read.
    946      * @throws  EOFException If end of file is reached.
    947      * @throws  IOException If other I/O error has occurred.
    948      */
    949     public short readShort()  throws IOException {
    950         return bin.readShort();
    951     }
    952 
    953     /**
    954      * Reads an unsigned 16 bit short.
    955      *
    956      * @return  the 16 bit short read.
    957      * @throws  EOFException If end of file is reached.
    958      * @throws  IOException If other I/O error has occurred.
    959      */
    960     public int readUnsignedShort() throws IOException {
    961         return bin.readUnsignedShort();
    962     }
    963 
    964     /**
    965      * Reads a 32 bit int.
    966      *
    967      * @return  the 32 bit integer read.
    968      * @throws  EOFException If end of file is reached.
    969      * @throws  IOException If other I/O error has occurred.
    970      */
    971     public int readInt()  throws IOException {
    972         return bin.readInt();
    973     }
    974 
    975     /**
    976      * Reads a 64 bit long.
    977      *
    978      * @return  the read 64 bit long.
    979      * @throws  EOFException If end of file is reached.
    980      * @throws  IOException If other I/O error has occurred.
    981      */
    982     public long readLong()  throws IOException {
    983         return bin.readLong();
    984     }
    985 
    986     /**
    987      * Reads a 32 bit float.
    988      *
    989      * @return  the 32 bit float read.
    990      * @throws  EOFException If end of file is reached.
    991      * @throws  IOException If other I/O error has occurred.
    992      */
    993     public float readFloat() throws IOException {
    994         return bin.readFloat();
    995     }
    996 
    997     /**
    998      * Reads a 64 bit double.
    999      *
   1000      * @return  the 64 bit double read.
   1001      * @throws  EOFException If end of file is reached.
   1002      * @throws  IOException If other I/O error has occurred.
   1003      */
   1004     public double readDouble() throws IOException {
   1005         return bin.readDouble();
   1006     }
   1007 
   1008     /**
   1009      * Reads bytes, blocking until all bytes are read.
   1010      *
   1011      * @param   buf the buffer into which the data is read
   1012      * @throws  EOFException If end of file is reached.
   1013      * @throws  IOException If other I/O error has occurred.
   1014      */
   1015     public void readFully(byte[] buf) throws IOException {
   1016         bin.readFully(buf, 0, buf.length, false);
   1017     }
   1018 
   1019     /**
   1020      * Reads bytes, blocking until all bytes are read.
   1021      *
   1022      * @param   buf the buffer into which the data is read
   1023      * @param   off the start offset of the data
   1024      * @param   len the maximum number of bytes to read
   1025      * @throws  EOFException If end of file is reached.
   1026      * @throws  IOException If other I/O error has occurred.
   1027      */
   1028     public void readFully(byte[] buf, int off, int len) throws IOException {
   1029         int endoff = off + len;
   1030         if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) {
   1031             throw new IndexOutOfBoundsException();
   1032         }
   1033         bin.readFully(buf, off, len, false);
   1034     }
   1035 
   1036     /**
   1037      * Skips bytes.
   1038      *
   1039      * @param   len the number of bytes to be skipped
   1040      * @return  the actual number of bytes skipped.
   1041      * @throws  IOException If an I/O error has occurred.
   1042      */
   1043     public int skipBytes(int len) throws IOException {
   1044         return bin.skipBytes(len);
   1045     }
   1046 
   1047     /**
   1048      * Reads in a line that has been terminated by a \n, \r, \r\n or EOF.
   1049      *
   1050      * @return  a String copy of the line.
   1051      * @throws  IOException if there are I/O errors while reading from the
   1052      *          underlying <code>InputStream</code>
   1053      * @deprecated This method does not properly convert bytes to characters.
   1054      *          see DataInputStream for the details and alternatives.
   1055      */
   1056     @Deprecated
   1057     public String readLine() throws IOException {
   1058         return bin.readLine();
   1059     }
   1060 
   1061     /**
   1062      * Reads a String in
   1063      * <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
   1064      * format.
   1065      *
   1066      * @return  the String.
   1067      * @throws  IOException if there are I/O errors while reading from the
   1068      *          underlying <code>InputStream</code>
   1069      * @throws  UTFDataFormatException if read bytes do not represent a valid
   1070      *          modified UTF-8 encoding of a string
   1071      */
   1072     public String readUTF() throws IOException {
   1073         return bin.readUTF();
   1074     }
   1075 
   1076     /**
   1077      * Provide access to the persistent fields read from the input stream.
   1078      */
   1079     public static abstract class GetField {
   1080 
   1081         /**
   1082          * Get the ObjectStreamClass that describes the fields in the stream.
   1083          *
   1084          * @return  the descriptor class that describes the serializable fields
   1085          */
   1086         public abstract ObjectStreamClass getObjectStreamClass();
   1087 
   1088         /**
   1089          * Return true if the named field is defaulted and has no value in this
   1090          * stream.
   1091          *
   1092          * @param  name the name of the field
   1093          * @return true, if and only if the named field is defaulted
   1094          * @throws IOException if there are I/O errors while reading from
   1095          *         the underlying <code>InputStream</code>
   1096          * @throws IllegalArgumentException if <code>name</code> does not
   1097          *         correspond to a serializable field
   1098          */
   1099         public abstract boolean defaulted(String name) throws IOException;
   1100 
   1101         /**
   1102          * Get the value of the named boolean field from the persistent field.
   1103          *
   1104          * @param  name the name of the field
   1105          * @param  val the default value to use if <code>name</code> does not
   1106          *         have a value
   1107          * @return the value of the named <code>boolean</code> field
   1108          * @throws IOException if there are I/O errors while reading from the
   1109          *         underlying <code>InputStream</code>
   1110          * @throws IllegalArgumentException if type of <code>name</code> is
   1111          *         not serializable or if the field type is incorrect
   1112          */
   1113         public abstract boolean get(String name, boolean val)
   1114             throws IOException;
   1115 
   1116         /**
   1117          * Get the value of the named byte field from the persistent field.
   1118          *
   1119          * @param  name the name of the field
   1120          * @param  val the default value to use if <code>name</code> does not
   1121          *         have a value
   1122          * @return the value of the named <code>byte</code> field
   1123          * @throws IOException if there are I/O errors while reading from the
   1124          *         underlying <code>InputStream</code>
   1125          * @throws IllegalArgumentException if type of <code>name</code> is
   1126          *         not serializable or if the field type is incorrect
   1127          */
   1128         public abstract byte get(String name, byte val) throws IOException;
   1129 
   1130         /**
   1131          * Get the value of the named char field from the persistent field.
   1132          *
   1133          * @param  name the name of the field
   1134          * @param  val the default value to use if <code>name</code> does not
   1135          *         have a value
   1136          * @return the value of the named <code>char</code> field
   1137          * @throws IOException if there are I/O errors while reading from the
   1138          *         underlying <code>InputStream</code>
   1139          * @throws IllegalArgumentException if type of <code>name</code> is
   1140          *         not serializable or if the field type is incorrect
   1141          */
   1142         public abstract char get(String name, char val) throws IOException;
   1143 
   1144         /**
   1145          * Get the value of the named short field from the persistent field.
   1146          *
   1147          * @param  name the name of the field
   1148          * @param  val the default value to use if <code>name</code> does not
   1149          *         have a value
   1150          * @return the value of the named <code>short</code> field
   1151          * @throws IOException if there are I/O errors while reading from the
   1152          *         underlying <code>InputStream</code>
   1153          * @throws IllegalArgumentException if type of <code>name</code> is
   1154          *         not serializable or if the field type is incorrect
   1155          */
   1156         public abstract short get(String name, short val) throws IOException;
   1157 
   1158         /**
   1159          * Get the value of the named int field from the persistent field.
   1160          *
   1161          * @param  name the name of the field
   1162          * @param  val the default value to use if <code>name</code> does not
   1163          *         have a value
   1164          * @return the value of the named <code>int</code> field
   1165          * @throws IOException if there are I/O errors while reading from the
   1166          *         underlying <code>InputStream</code>
   1167          * @throws IllegalArgumentException if type of <code>name</code> is
   1168          *         not serializable or if the field type is incorrect
   1169          */
   1170         public abstract int get(String name, int val) throws IOException;
   1171 
   1172         /**
   1173          * Get the value of the named long field from the persistent field.
   1174          *
   1175          * @param  name the name of the field
   1176          * @param  val the default value to use if <code>name</code> does not
   1177          *         have a value
   1178          * @return the value of the named <code>long</code> field
   1179          * @throws IOException if there are I/O errors while reading from the
   1180          *         underlying <code>InputStream</code>
   1181          * @throws IllegalArgumentException if type of <code>name</code> is
   1182          *         not serializable or if the field type is incorrect
   1183          */
   1184         public abstract long get(String name, long val) throws IOException;
   1185 
   1186         /**
   1187          * Get the value of the named float field from the persistent field.
   1188          *
   1189          * @param  name the name of the field
   1190          * @param  val the default value to use if <code>name</code> does not
   1191          *         have a value
   1192          * @return the value of the named <code>float</code> field
   1193          * @throws IOException if there are I/O errors while reading from the
   1194          *         underlying <code>InputStream</code>
   1195          * @throws IllegalArgumentException if type of <code>name</code> is
   1196          *         not serializable or if the field type is incorrect
   1197          */
   1198         public abstract float get(String name, float val) throws IOException;
   1199 
   1200         /**
   1201          * Get the value of the named double field from the persistent field.
   1202          *
   1203          * @param  name the name of the field
   1204          * @param  val the default value to use if <code>name</code> does not
   1205          *         have a value
   1206          * @return the value of the named <code>double</code> field
   1207          * @throws IOException if there are I/O errors while reading from the
   1208          *         underlying <code>InputStream</code>
   1209          * @throws IllegalArgumentException if type of <code>name</code> is
   1210          *         not serializable or if the field type is incorrect
   1211          */
   1212         public abstract double get(String name, double val) throws IOException;
   1213 
   1214         /**
   1215          * Get the value of the named Object field from the persistent field.
   1216          *
   1217          * @param  name the name of the field
   1218          * @param  val the default value to use if <code>name</code> does not
   1219          *         have a value
   1220          * @return the value of the named <code>Object</code> field
   1221          * @throws IOException if there are I/O errors while reading from the
   1222          *         underlying <code>InputStream</code>
   1223          * @throws IllegalArgumentException if type of <code>name</code> is
   1224          *         not serializable or if the field type is incorrect
   1225          */
   1226         public abstract Object get(String name, Object val) throws IOException;
   1227     }
   1228 
   1229     /**
   1230      * Verifies that this (possibly subclass) instance can be constructed
   1231      * without violating security constraints: the subclass must not override
   1232      * security-sensitive non-final methods, or else the
   1233      * "enableSubclassImplementation" SerializablePermission is checked.
   1234      */
   1235     private void verifySubclass() {
   1236         Class cl = getClass();
   1237         if (cl == ObjectInputStream.class) {
   1238             return;
   1239         }
   1240         SecurityManager sm = System.getSecurityManager();
   1241         if (sm == null) {
   1242             return;
   1243         }
   1244         processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits);
   1245         WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue);
   1246         Boolean result = Caches.subclassAudits.get(key);
   1247         if (result == null) {
   1248             result = Boolean.valueOf(auditSubclass(cl));
   1249             Caches.subclassAudits.putIfAbsent(key, result);
   1250         }
   1251         if (result.booleanValue()) {
   1252             return;
   1253         }
   1254         sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
   1255     }
   1256 
   1257     /**
   1258      * Performs reflective checks on given subclass to verify that it doesn't
   1259      * override security-sensitive non-final methods.  Returns true if subclass
   1260      * is "safe", false otherwise.
   1261      */
   1262     private static boolean auditSubclass(final Class<?> subcl) {
   1263         Boolean result = AccessController.doPrivileged(
   1264             new PrivilegedAction<Boolean>() {
   1265                 public Boolean run() {
   1266                     for (Class<?> cl = subcl;
   1267                          cl != ObjectInputStream.class;
   1268                          cl = cl.getSuperclass())
   1269                     {
   1270                         try {
   1271                             cl.getDeclaredMethod(
   1272                                 "readUnshared", (Class[]) null);
   1273                             return Boolean.FALSE;
   1274                         } catch (NoSuchMethodException ex) {
   1275                         }
   1276                         try {
   1277                             cl.getDeclaredMethod("readFields", (Class[]) null);
   1278                             return Boolean.FALSE;
   1279                         } catch (NoSuchMethodException ex) {
   1280                         }
   1281                     }
   1282                     return Boolean.TRUE;
   1283                 }
   1284             }
   1285         );
   1286         return result.booleanValue();
   1287     }
   1288 
   1289     /**
   1290      * Clears internal data structures.
   1291      */
   1292     private void clear() {
   1293         handles.clear();
   1294         vlist.clear();
   1295     }
   1296 
   1297     /**
   1298      * Underlying readObject implementation.
   1299      */
   1300     private Object readObject0(boolean unshared) throws IOException {
   1301         boolean oldMode = bin.getBlockDataMode();
   1302         if (oldMode) {
   1303             int remain = bin.currentBlockRemaining();
   1304             if (remain > 0) {
   1305                 throw new OptionalDataException(remain);
   1306             } else if (defaultDataEnd) {
   1307                 /*
   1308                  * Fix for 4360508: stream is currently at the end of a field
   1309                  * value block written via default serialization; since there
   1310                  * is no terminating TC_ENDBLOCKDATA tag, simulate
   1311                  * end-of-custom-data behavior explicitly.
   1312                  */
   1313                 throw new OptionalDataException(true);
   1314             }
   1315             bin.setBlockDataMode(false);
   1316         }
   1317 
   1318         byte tc;
   1319         while ((tc = bin.peekByte()) == TC_RESET) {
   1320             bin.readByte();
   1321             handleReset();
   1322         }
   1323 
   1324         depth++;
   1325         try {
   1326             switch (tc) {
   1327                 case TC_NULL:
   1328                     return readNull();
   1329 
   1330                 case TC_REFERENCE:
   1331                     return readHandle(unshared);
   1332 
   1333                 case TC_CLASS:
   1334                     return readClass(unshared);
   1335 
   1336                 case TC_CLASSDESC:
   1337                 case TC_PROXYCLASSDESC:
   1338                     return readClassDesc(unshared);
   1339 
   1340                 case TC_STRING:
   1341                 case TC_LONGSTRING:
   1342                     return checkResolve(readString(unshared));
   1343 
   1344                 case TC_ARRAY:
   1345                     return checkResolve(readArray(unshared));
   1346 
   1347                 case TC_ENUM:
   1348                     return checkResolve(readEnum(unshared));
   1349 
   1350                 case TC_OBJECT:
   1351                     return checkResolve(readOrdinaryObject(unshared));
   1352 
   1353                 case TC_EXCEPTION:
   1354                     IOException ex = readFatalException();
   1355                     throw new WriteAbortedException("writing aborted", ex);
   1356 
   1357                 case TC_BLOCKDATA:
   1358                 case TC_BLOCKDATALONG:
   1359                     if (oldMode) {
   1360                         bin.setBlockDataMode(true);
   1361                         bin.peek();             // force header read
   1362                         throw new OptionalDataException(
   1363                             bin.currentBlockRemaining());
   1364                     } else {
   1365                         throw new StreamCorruptedException(
   1366                             "unexpected block data");
   1367                     }
   1368 
   1369                 case TC_ENDBLOCKDATA:
   1370                     if (oldMode) {
   1371                         throw new OptionalDataException(true);
   1372                     } else {
   1373                         throw new StreamCorruptedException(
   1374                             "unexpected end of block data");
   1375                     }
   1376 
   1377                 default:
   1378                     throw new StreamCorruptedException(
   1379                         String.format("invalid type code: %02X", tc));
   1380             }
   1381         } finally {
   1382             depth--;
   1383             bin.setBlockDataMode(oldMode);
   1384         }
   1385     }
   1386 
   1387     /**
   1388      * If resolveObject has been enabled and given object does not have an
   1389      * exception associated with it, calls resolveObject to determine
   1390      * replacement for object, and updates handle table accordingly.  Returns
   1391      * replacement object, or echoes provided object if no replacement
   1392      * occurred.  Expects that passHandle is set to given object's handle prior
   1393      * to calling this method.
   1394      */
   1395     private Object checkResolve(Object obj) throws IOException {
   1396         if (!enableResolve || handles.lookupException(passHandle) != null) {
   1397             return obj;
   1398         }
   1399         Object rep = resolveObject(obj);
   1400         if (rep != obj) {
   1401             handles.setObject(passHandle, rep);
   1402         }
   1403         return rep;
   1404     }
   1405 
   1406     /**
   1407      * Reads string without allowing it to be replaced in stream.  Called from
   1408      * within ObjectStreamClass.read().
   1409      */
   1410     String readTypeString() throws IOException {
   1411         int oldHandle = passHandle;
   1412         try {
   1413             byte tc = bin.peekByte();
   1414             switch (tc) {
   1415                 case TC_NULL:
   1416                     return (String) readNull();
   1417 
   1418                 case TC_REFERENCE:
   1419                     return (String) readHandle(false);
   1420 
   1421                 case TC_STRING:
   1422                 case TC_LONGSTRING:
   1423                     return readString(false);
   1424 
   1425                 default:
   1426                     throw new StreamCorruptedException(
   1427                         String.format("invalid type code: %02X", tc));
   1428             }
   1429         } finally {
   1430             passHandle = oldHandle;
   1431         }
   1432     }
   1433 
   1434     /**
   1435      * Reads in null code, sets passHandle to NULL_HANDLE and returns null.
   1436      */
   1437     private Object readNull() throws IOException {
   1438         if (bin.readByte() != TC_NULL) {
   1439             throw new InternalError();
   1440         }
   1441         passHandle = NULL_HANDLE;
   1442         return null;
   1443     }
   1444 
   1445     /**
   1446      * Reads in object handle, sets passHandle to the read handle, and returns
   1447      * object associated with the handle.
   1448      */
   1449     private Object readHandle(boolean unshared) throws IOException {
   1450         if (bin.readByte() != TC_REFERENCE) {
   1451             throw new InternalError();
   1452         }
   1453         passHandle = bin.readInt() - baseWireHandle;
   1454         if (passHandle < 0 || passHandle >= handles.size()) {
   1455             throw new StreamCorruptedException(
   1456                 String.format("invalid handle value: %08X", passHandle +
   1457                 baseWireHandle));
   1458         }
   1459         if (unshared) {
   1460             // REMIND: what type of exception to throw here?
   1461             throw new InvalidObjectException(
   1462                 "cannot read back reference as unshared");
   1463         }
   1464 
   1465         Object obj = handles.lookupObject(passHandle);
   1466         if (obj == unsharedMarker) {
   1467             // REMIND: what type of exception to throw here?
   1468             throw new InvalidObjectException(
   1469                 "cannot read back reference to unshared object");
   1470         }
   1471         return obj;
   1472     }
   1473 
   1474     /**
   1475      * Reads in and returns class object.  Sets passHandle to class object's
   1476      * assigned handle.  Returns null if class is unresolvable (in which case a
   1477      * ClassNotFoundException will be associated with the class' handle in the
   1478      * handle table).
   1479      */
   1480     private Class readClass(boolean unshared) throws IOException {
   1481         if (bin.readByte() != TC_CLASS) {
   1482             throw new InternalError();
   1483         }
   1484         ObjectStreamClass desc = readClassDesc(false);
   1485         Class cl = desc.forClass();
   1486         passHandle = handles.assign(unshared ? unsharedMarker : cl);
   1487 
   1488         ClassNotFoundException resolveEx = desc.getResolveException();
   1489         if (resolveEx != null) {
   1490             handles.markException(passHandle, resolveEx);
   1491         }
   1492 
   1493         handles.finish(passHandle);
   1494         return cl;
   1495     }
   1496 
   1497     /**
   1498      * Reads in and returns (possibly null) class descriptor.  Sets passHandle
   1499      * to class descriptor's assigned handle.  If class descriptor cannot be
   1500      * resolved to a class in the local VM, a ClassNotFoundException is
   1501      * associated with the class descriptor's handle.
   1502      */
   1503     private ObjectStreamClass readClassDesc(boolean unshared)
   1504         throws IOException
   1505     {
   1506         byte tc = bin.peekByte();
   1507         switch (tc) {
   1508             case TC_NULL:
   1509                 return (ObjectStreamClass) readNull();
   1510 
   1511             case TC_REFERENCE:
   1512                 return (ObjectStreamClass) readHandle(unshared);
   1513 
   1514             case TC_PROXYCLASSDESC:
   1515                 return readProxyDesc(unshared);
   1516 
   1517             case TC_CLASSDESC:
   1518                 return readNonProxyDesc(unshared);
   1519 
   1520             default:
   1521                 throw new StreamCorruptedException(
   1522                     String.format("invalid type code: %02X", tc));
   1523         }
   1524     }
   1525 
   1526     private boolean isCustomSubclass() {
   1527         // Return true if this class is a custom subclass of ObjectInputStream
   1528         return getClass().getClassLoader()
   1529                     != ObjectInputStream.class.getClassLoader();
   1530     }
   1531 
   1532     /**
   1533      * Reads in and returns class descriptor for a dynamic proxy class.  Sets
   1534      * passHandle to proxy class descriptor's assigned handle.  If proxy class
   1535      * descriptor cannot be resolved to a class in the local VM, a
   1536      * ClassNotFoundException is associated with the descriptor's handle.
   1537      */
   1538     private ObjectStreamClass readProxyDesc(boolean unshared)
   1539         throws IOException
   1540     {
   1541         if (bin.readByte() != TC_PROXYCLASSDESC) {
   1542             throw new InternalError();
   1543         }
   1544 
   1545         ObjectStreamClass desc = new ObjectStreamClass();
   1546         int descHandle = handles.assign(unshared ? unsharedMarker : desc);
   1547         passHandle = NULL_HANDLE;
   1548 
   1549         int numIfaces = bin.readInt();
   1550         String[] ifaces = new String[numIfaces];
   1551         for (int i = 0; i < numIfaces; i++) {
   1552             ifaces[i] = bin.readUTF();
   1553         }
   1554 
   1555         Class cl = null;
   1556         ClassNotFoundException resolveEx = null;
   1557         bin.setBlockDataMode(true);
   1558         try {
   1559             if ((cl = resolveProxyClass(ifaces)) == null) {
   1560                 resolveEx = new ClassNotFoundException("null class");
   1561             } else if (!Proxy.isProxyClass(cl)) {
   1562                 throw new InvalidClassException("Not a proxy");
   1563             } else {
   1564                 // ReflectUtil.checkProxyPackageAccess makes a test
   1565                 // equivalent to isCustomSubclass so there's no need
   1566                 // to condition this call to isCustomSubclass == true here.
   1567                 ReflectUtil.checkProxyPackageAccess(
   1568                         getClass().getClassLoader(),
   1569                         cl.getInterfaces());
   1570             }
   1571         } catch (ClassNotFoundException ex) {
   1572             resolveEx = ex;
   1573         }
   1574         skipCustomData();
   1575 
   1576         desc.initProxy(cl, resolveEx, readClassDesc(false));
   1577 
   1578         handles.finish(descHandle);
   1579         passHandle = descHandle;
   1580         return desc;
   1581     }
   1582 
   1583     /**
   1584      * Reads in and returns class descriptor for a class that is not a dynamic
   1585      * proxy class.  Sets passHandle to class descriptor's assigned handle.  If
   1586      * class descriptor cannot be resolved to a class in the local VM, a
   1587      * ClassNotFoundException is associated with the descriptor's handle.
   1588      */
   1589     private ObjectStreamClass readNonProxyDesc(boolean unshared)
   1590         throws IOException
   1591     {
   1592         if (bin.readByte() != TC_CLASSDESC) {
   1593             throw new InternalError();
   1594         }
   1595 
   1596         ObjectStreamClass desc = new ObjectStreamClass();
   1597         int descHandle = handles.assign(unshared ? unsharedMarker : desc);
   1598         passHandle = NULL_HANDLE;
   1599 
   1600         ObjectStreamClass readDesc = null;
   1601         try {
   1602             readDesc = readClassDescriptor();
   1603         } catch (ClassNotFoundException ex) {
   1604             throw (IOException) new InvalidClassException(
   1605                 "failed to read class descriptor").initCause(ex);
   1606         }
   1607 
   1608         Class cl = null;
   1609         ClassNotFoundException resolveEx = null;
   1610         bin.setBlockDataMode(true);
   1611         final boolean checksRequired = isCustomSubclass();
   1612         try {
   1613             if ((cl = resolveClass(readDesc)) == null) {
   1614                 resolveEx = new ClassNotFoundException("null class");
   1615             } else if (checksRequired) {
   1616                 ReflectUtil.checkPackageAccess(cl);
   1617             }
   1618         } catch (ClassNotFoundException ex) {
   1619             resolveEx = ex;
   1620         }
   1621         skipCustomData();
   1622 
   1623         desc.initNonProxy(readDesc, cl, resolveEx, readClassDesc(false));
   1624 
   1625         handles.finish(descHandle);
   1626         passHandle = descHandle;
   1627         return desc;
   1628     }
   1629 
   1630     /**
   1631      * Reads in and returns new string.  Sets passHandle to new string's
   1632      * assigned handle.
   1633      */
   1634     private String readString(boolean unshared) throws IOException {
   1635         String str;
   1636         byte tc = bin.readByte();
   1637         switch (tc) {
   1638             case TC_STRING:
   1639                 str = bin.readUTF();
   1640                 break;
   1641 
   1642             case TC_LONGSTRING:
   1643                 str = bin.readLongUTF();
   1644                 break;
   1645 
   1646             default:
   1647                 throw new StreamCorruptedException(
   1648                     String.format("invalid type code: %02X", tc));
   1649         }
   1650         passHandle = handles.assign(unshared ? unsharedMarker : str);
   1651         handles.finish(passHandle);
   1652         return str;
   1653     }
   1654 
   1655     /**
   1656      * Reads in and returns array object, or null if array class is
   1657      * unresolvable.  Sets passHandle to array's assigned handle.
   1658      */
   1659     private Object readArray(boolean unshared) throws IOException {
   1660         if (bin.readByte() != TC_ARRAY) {
   1661             throw new InternalError();
   1662         }
   1663 
   1664         ObjectStreamClass desc = readClassDesc(false);
   1665         int len = bin.readInt();
   1666 
   1667         Object array = null;
   1668         Class cl, ccl = null;
   1669         if ((cl = desc.forClass()) != null) {
   1670             ccl = cl.getComponentType();
   1671             array = Array.newInstance(ccl, len);
   1672         }
   1673 
   1674         int arrayHandle = handles.assign(unshared ? unsharedMarker : array);
   1675         ClassNotFoundException resolveEx = desc.getResolveException();
   1676         if (resolveEx != null) {
   1677             handles.markException(arrayHandle, resolveEx);
   1678         }
   1679 
   1680         if (ccl == null) {
   1681             for (int i = 0; i < len; i++) {
   1682                 readObject0(false);
   1683             }
   1684         } else if (ccl.isPrimitive()) {
   1685             if (ccl == Integer.TYPE) {
   1686                 bin.readInts((int[]) array, 0, len);
   1687             } else if (ccl == Byte.TYPE) {
   1688                 bin.readFully((byte[]) array, 0, len, true);
   1689             } else if (ccl == Long.TYPE) {
   1690                 bin.readLongs((long[]) array, 0, len);
   1691             } else if (ccl == Float.TYPE) {
   1692                 bin.readFloats((float[]) array, 0, len);
   1693             } else if (ccl == Double.TYPE) {
   1694                 bin.readDoubles((double[]) array, 0, len);
   1695             } else if (ccl == Short.TYPE) {
   1696                 bin.readShorts((short[]) array, 0, len);
   1697             } else if (ccl == Character.TYPE) {
   1698                 bin.readChars((char[]) array, 0, len);
   1699             } else if (ccl == Boolean.TYPE) {
   1700                 bin.readBooleans((boolean[]) array, 0, len);
   1701             } else {
   1702                 throw new InternalError();
   1703             }
   1704         } else {
   1705             Object[] oa = (Object[]) array;
   1706             for (int i = 0; i < len; i++) {
   1707                 oa[i] = readObject0(false);
   1708                 handles.markDependency(arrayHandle, passHandle);
   1709             }
   1710         }
   1711 
   1712         handles.finish(arrayHandle);
   1713         passHandle = arrayHandle;
   1714         return array;
   1715     }
   1716 
   1717     /**
   1718      * Reads in and returns enum constant, or null if enum type is
   1719      * unresolvable.  Sets passHandle to enum constant's assigned handle.
   1720      */
   1721     private Enum readEnum(boolean unshared) throws IOException {
   1722         if (bin.readByte() != TC_ENUM) {
   1723             throw new InternalError();
   1724         }
   1725 
   1726         ObjectStreamClass desc = readClassDesc(false);
   1727         if (!desc.isEnum()) {
   1728             throw new InvalidClassException("non-enum class: " + desc);
   1729         }
   1730 
   1731         int enumHandle = handles.assign(unshared ? unsharedMarker : null);
   1732         ClassNotFoundException resolveEx = desc.getResolveException();
   1733         if (resolveEx != null) {
   1734             handles.markException(enumHandle, resolveEx);
   1735         }
   1736 
   1737         String name = readString(false);
   1738         Enum en = null;
   1739         Class cl = desc.forClass();
   1740         if (cl != null) {
   1741             try {
   1742                 en = Enum.valueOf(cl, name);
   1743             } catch (IllegalArgumentException ex) {
   1744                 throw (IOException) new InvalidObjectException(
   1745                     "enum constant " + name + " does not exist in " +
   1746                     cl).initCause(ex);
   1747             }
   1748             if (!unshared) {
   1749                 handles.setObject(enumHandle, en);
   1750             }
   1751         }
   1752 
   1753         handles.finish(enumHandle);
   1754         passHandle = enumHandle;
   1755         return en;
   1756     }
   1757 
   1758     /**
   1759      * Reads and returns "ordinary" (i.e., not a String, Class,
   1760      * ObjectStreamClass, array, or enum constant) object, or null if object's
   1761      * class is unresolvable (in which case a ClassNotFoundException will be
   1762      * associated with object's handle).  Sets passHandle to object's assigned
   1763      * handle.
   1764      */
   1765     private Object readOrdinaryObject(boolean unshared)
   1766         throws IOException
   1767     {
   1768         if (bin.readByte() != TC_OBJECT) {
   1769             throw new InternalError();
   1770         }
   1771 
   1772         ObjectStreamClass desc = readClassDesc(false);
   1773         desc.checkDeserialize();
   1774 
   1775         Class<?> cl = desc.forClass();
   1776         if (cl == String.class || cl == Class.class
   1777                 || cl == ObjectStreamClass.class) {
   1778             throw new InvalidClassException("invalid class descriptor");
   1779         }
   1780 
   1781         Object obj;
   1782         try {
   1783             obj = desc.isInstantiable() ? desc.newInstance() : null;
   1784         } catch (Exception ex) {
   1785             throw (IOException) new InvalidClassException(
   1786                 desc.forClass().getName(),
   1787                 "unable to create instance").initCause(ex);
   1788         }
   1789 
   1790         passHandle = handles.assign(unshared ? unsharedMarker : obj);
   1791         ClassNotFoundException resolveEx = desc.getResolveException();
   1792         if (resolveEx != null) {
   1793             handles.markException(passHandle, resolveEx);
   1794         }
   1795 
   1796         if (desc.isExternalizable()) {
   1797             readExternalData((Externalizable) obj, desc);
   1798         } else {
   1799             readSerialData(obj, desc);
   1800         }
   1801 
   1802         handles.finish(passHandle);
   1803 
   1804         if (obj != null &&
   1805             handles.lookupException(passHandle) == null &&
   1806             desc.hasReadResolveMethod())
   1807         {
   1808             Object rep = desc.invokeReadResolve(obj);
   1809             if (unshared && rep.getClass().isArray()) {
   1810                 rep = cloneArray(rep);
   1811             }
   1812             if (rep != obj) {
   1813                 handles.setObject(passHandle, obj = rep);
   1814             }
   1815         }
   1816 
   1817         return obj;
   1818     }
   1819 
   1820     /**
   1821      * If obj is non-null, reads externalizable data by invoking readExternal()
   1822      * method of obj; otherwise, attempts to skip over externalizable data.
   1823      * Expects that passHandle is set to obj's handle before this method is
   1824      * called.
   1825      */
   1826     private void readExternalData(Externalizable obj, ObjectStreamClass desc)
   1827         throws IOException
   1828     {
   1829         SerialCallbackContext oldContext = curContext;
   1830         curContext = null;
   1831         try {
   1832             boolean blocked = desc.hasBlockExternalData();
   1833             if (blocked) {
   1834                 bin.setBlockDataMode(true);
   1835             }
   1836             if (obj != null) {
   1837                 try {
   1838                     obj.readExternal(this);
   1839                 } catch (ClassNotFoundException ex) {
   1840                     /*
   1841                      * In most cases, the handle table has already propagated
   1842                      * a CNFException to passHandle at this point; this mark
   1843                      * call is included to address cases where the readExternal
   1844                      * method has cons'ed and thrown a new CNFException of its
   1845                      * own.
   1846                      */
   1847                      handles.markException(passHandle, ex);
   1848                 }
   1849             }
   1850             if (blocked) {
   1851                 skipCustomData();
   1852             }
   1853         } finally {
   1854             curContext = oldContext;
   1855         }
   1856         /*
   1857          * At this point, if the externalizable data was not written in
   1858          * block-data form and either the externalizable class doesn't exist
   1859          * locally (i.e., obj == null) or readExternal() just threw a
   1860          * CNFException, then the stream is probably in an inconsistent state,
   1861          * since some (or all) of the externalizable data may not have been
   1862          * consumed.  Since there's no "correct" action to take in this case,
   1863          * we mimic the behavior of past serialization implementations and
   1864          * blindly hope that the stream is in sync; if it isn't and additional
   1865          * externalizable data remains in the stream, a subsequent read will
   1866          * most likely throw a StreamCorruptedException.
   1867          */
   1868     }
   1869 
   1870     /**
   1871      * Reads (or attempts to skip, if obj is null or is tagged with a
   1872      * ClassNotFoundException) instance data for each serializable class of
   1873      * object in stream, from superclass to subclass.  Expects that passHandle
   1874      * is set to obj's handle before this method is called.
   1875      */
   1876     private void readSerialData(Object obj, ObjectStreamClass desc)
   1877         throws IOException
   1878     {
   1879         ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
   1880         for (int i = 0; i < slots.length; i++) {
   1881             ObjectStreamClass slotDesc = slots[i].desc;
   1882 
   1883             if (slots[i].hasData) {
   1884                 if (obj != null &&
   1885                     slotDesc.hasReadObjectMethod() &&
   1886                     handles.lookupException(passHandle) == null)
   1887                 {
   1888                     SerialCallbackContext oldContext = curContext;
   1889 
   1890                     try {
   1891                         curContext = new SerialCallbackContext(obj, slotDesc);
   1892 
   1893                         bin.setBlockDataMode(true);
   1894                         slotDesc.invokeReadObject(obj, this);
   1895                     } catch (ClassNotFoundException ex) {
   1896                         /*
   1897                          * In most cases, the handle table has already
   1898                          * propagated a CNFException to passHandle at this
   1899                          * point; this mark call is included to address cases
   1900                          * where the custom readObject method has cons'ed and
   1901                          * thrown a new CNFException of its own.
   1902                          */
   1903                         handles.markException(passHandle, ex);
   1904                     } finally {
   1905                         curContext.setUsed();
   1906                         curContext = oldContext;
   1907                     }
   1908 
   1909                     /*
   1910                      * defaultDataEnd may have been set indirectly by custom
   1911                      * readObject() method when calling defaultReadObject() or
   1912                      * readFields(); clear it to restore normal read behavior.
   1913                      */
   1914                     defaultDataEnd = false;
   1915                 } else {
   1916                     defaultReadFields(obj, slotDesc);
   1917                 }
   1918                 if (slotDesc.hasWriteObjectData()) {
   1919                     skipCustomData();
   1920                 } else {
   1921                     bin.setBlockDataMode(false);
   1922                 }
   1923             } else {
   1924                 if (obj != null &&
   1925                     slotDesc.hasReadObjectNoDataMethod() &&
   1926                     handles.lookupException(passHandle) == null)
   1927                 {
   1928                     slotDesc.invokeReadObjectNoData(obj);
   1929                 }
   1930             }
   1931         }
   1932     }
   1933 
   1934     /**
   1935      * Skips over all block data and objects until TC_ENDBLOCKDATA is
   1936      * encountered.
   1937      */
   1938     private void skipCustomData() throws IOException {
   1939         int oldHandle = passHandle;
   1940         for (;;) {
   1941             if (bin.getBlockDataMode()) {
   1942                 bin.skipBlockData();
   1943                 bin.setBlockDataMode(false);
   1944             }
   1945             switch (bin.peekByte()) {
   1946                 case TC_BLOCKDATA:
   1947                 case TC_BLOCKDATALONG:
   1948                     bin.setBlockDataMode(true);
   1949                     break;
   1950 
   1951                 case TC_ENDBLOCKDATA:
   1952                     bin.readByte();
   1953                     passHandle = oldHandle;
   1954                     return;
   1955 
   1956                 default:
   1957                     readObject0(false);
   1958                     break;
   1959             }
   1960         }
   1961     }
   1962 
   1963     /**
   1964      * Reads in values of serializable fields declared by given class
   1965      * descriptor.  If obj is non-null, sets field values in obj.  Expects that
   1966      * passHandle is set to obj's handle before this method is called.
   1967      */
   1968     private void defaultReadFields(Object obj, ObjectStreamClass desc)
   1969         throws IOException
   1970     {
   1971         // REMIND: is isInstance check necessary?
   1972         Class cl = desc.forClass();
   1973         if (cl != null && obj != null && !cl.isInstance(obj)) {
   1974             throw new ClassCastException();
   1975         }
   1976 
   1977         int primDataSize = desc.getPrimDataSize();
   1978         if (primVals == null || primVals.length < primDataSize) {
   1979             primVals = new byte[primDataSize];
   1980         }
   1981         bin.readFully(primVals, 0, primDataSize, false);
   1982         if (obj != null) {
   1983             desc.setPrimFieldValues(obj, primVals);
   1984         }
   1985 
   1986         int objHandle = passHandle;
   1987         ObjectStreamField[] fields = desc.getFields(false);
   1988         Object[] objVals = new Object[desc.getNumObjFields()];
   1989         int numPrimFields = fields.length - objVals.length;
   1990         for (int i = 0; i < objVals.length; i++) {
   1991             ObjectStreamField f = fields[numPrimFields + i];
   1992             objVals[i] = readObject0(f.isUnshared());
   1993             if (f.getField() != null) {
   1994                 handles.markDependency(objHandle, passHandle);
   1995             }
   1996         }
   1997         if (obj != null) {
   1998             desc.setObjFieldValues(obj, objVals);
   1999         }
   2000         passHandle = objHandle;
   2001     }
   2002 
   2003     /**
   2004      * Reads in and returns IOException that caused serialization to abort.
   2005      * All stream state is discarded prior to reading in fatal exception.  Sets
   2006      * passHandle to fatal exception's handle.
   2007      */
   2008     private IOException readFatalException() throws IOException {
   2009         if (bin.readByte() != TC_EXCEPTION) {
   2010             throw new InternalError();
   2011         }
   2012         clear();
   2013         IOException e = (IOException) readObject0(false);
   2014         // ----- BEGIN android -----
   2015         clear();
   2016         // ----- END android -----
   2017         return e;
   2018     }
   2019 
   2020     /**
   2021      * If recursion depth is 0, clears internal data structures; otherwise,
   2022      * throws a StreamCorruptedException.  This method is called when a
   2023      * TC_RESET typecode is encountered.
   2024      */
   2025     private void handleReset() throws StreamCorruptedException {
   2026         if (depth > 0) {
   2027             throw new StreamCorruptedException(
   2028                 "unexpected reset; recursion depth: " + depth);
   2029         }
   2030         clear();
   2031     }
   2032 
   2033     /**
   2034      * Converts specified span of bytes into float values.
   2035      */
   2036     // REMIND: remove once hotspot inlines Float.intBitsToFloat
   2037     private static native void bytesToFloats(byte[] src, int srcpos,
   2038                                              float[] dst, int dstpos,
   2039                                              int nfloats);
   2040 
   2041     /**
   2042      * Converts specified span of bytes into double values.
   2043      */
   2044     // REMIND: remove once hotspot inlines Double.longBitsToDouble
   2045     private static native void bytesToDoubles(byte[] src, int srcpos,
   2046                                               double[] dst, int dstpos,
   2047                                               int ndoubles);
   2048 
   2049     /**
   2050      * Returns the first non-null class loader (not counting class loaders of
   2051      * generated reflection implementation classes) up the execution stack, or
   2052      * null if only code from the null class loader is on the stack.  This
   2053      * method is also called via reflection by the following RMI-IIOP class:
   2054      *
   2055      *     com.sun.corba.se.internal.util.JDKClassLoader
   2056      *
   2057      * This method should not be removed or its signature changed without
   2058      * corresponding modifications to the above class.
   2059      */
   2060     private static ClassLoader latestUserDefinedLoader() {
   2061         return VMStack.getClosestUserClassLoader();
   2062     }
   2063 
   2064     /**
   2065      * Default GetField implementation.
   2066      */
   2067     private class GetFieldImpl extends GetField {
   2068 
   2069         /** class descriptor describing serializable fields */
   2070         private final ObjectStreamClass desc;
   2071         /** primitive field values */
   2072         private final byte[] primVals;
   2073         /** object field values */
   2074         private final Object[] objVals;
   2075         /** object field value handles */
   2076         private final int[] objHandles;
   2077 
   2078         /**
   2079          * Creates GetFieldImpl object for reading fields defined in given
   2080          * class descriptor.
   2081          */
   2082         GetFieldImpl(ObjectStreamClass desc) {
   2083             this.desc = desc;
   2084             primVals = new byte[desc.getPrimDataSize()];
   2085             objVals = new Object[desc.getNumObjFields()];
   2086             objHandles = new int[objVals.length];
   2087         }
   2088 
   2089         public ObjectStreamClass getObjectStreamClass() {
   2090             return desc;
   2091         }
   2092 
   2093         public boolean defaulted(String name) throws IOException {
   2094             return (getFieldOffset(name, null) < 0);
   2095         }
   2096 
   2097         public boolean get(String name, boolean val) throws IOException {
   2098             int off = getFieldOffset(name, Boolean.TYPE);
   2099             return (off >= 0) ? Bits.getBoolean(primVals, off) : val;
   2100         }
   2101 
   2102         public byte get(String name, byte val) throws IOException {
   2103             int off = getFieldOffset(name, Byte.TYPE);
   2104             return (off >= 0) ? primVals[off] : val;
   2105         }
   2106 
   2107         public char get(String name, char val) throws IOException {
   2108             int off = getFieldOffset(name, Character.TYPE);
   2109             return (off >= 0) ? Bits.getChar(primVals, off) : val;
   2110         }
   2111 
   2112         public short get(String name, short val) throws IOException {
   2113             int off = getFieldOffset(name, Short.TYPE);
   2114             return (off >= 0) ? Bits.getShort(primVals, off) : val;
   2115         }
   2116 
   2117         public int get(String name, int val) throws IOException {
   2118             int off = getFieldOffset(name, Integer.TYPE);
   2119             return (off >= 0) ? Bits.getInt(primVals, off) : val;
   2120         }
   2121 
   2122         public float get(String name, float val) throws IOException {
   2123             int off = getFieldOffset(name, Float.TYPE);
   2124             return (off >= 0) ? Bits.getFloat(primVals, off) : val;
   2125         }
   2126 
   2127         public long get(String name, long val) throws IOException {
   2128             int off = getFieldOffset(name, Long.TYPE);
   2129             return (off >= 0) ? Bits.getLong(primVals, off) : val;
   2130         }
   2131 
   2132         public double get(String name, double val) throws IOException {
   2133             int off = getFieldOffset(name, Double.TYPE);
   2134             return (off >= 0) ? Bits.getDouble(primVals, off) : val;
   2135         }
   2136 
   2137         public Object get(String name, Object val) throws IOException {
   2138             int off = getFieldOffset(name, Object.class);
   2139             if (off >= 0) {
   2140                 int objHandle = objHandles[off];
   2141                 handles.markDependency(passHandle, objHandle);
   2142                 return (handles.lookupException(objHandle) == null) ?
   2143                     objVals[off] : null;
   2144             } else {
   2145                 return val;
   2146             }
   2147         }
   2148 
   2149         /**
   2150          * Reads primitive and object field values from stream.
   2151          */
   2152         void readFields() throws IOException {
   2153             bin.readFully(primVals, 0, primVals.length, false);
   2154 
   2155             int oldHandle = passHandle;
   2156             ObjectStreamField[] fields = desc.getFields(false);
   2157             int numPrimFields = fields.length - objVals.length;
   2158             for (int i = 0; i < objVals.length; i++) {
   2159                 objVals[i] =
   2160                     readObject0(fields[numPrimFields + i].isUnshared());
   2161                 objHandles[i] = passHandle;
   2162             }
   2163             passHandle = oldHandle;
   2164         }
   2165 
   2166         /**
   2167          * Returns offset of field with given name and type.  A specified type
   2168          * of null matches all types, Object.class matches all non-primitive
   2169          * types, and any other non-null type matches assignable types only.
   2170          * If no matching field is found in the (incoming) class
   2171          * descriptor but a matching field is present in the associated local
   2172          * class descriptor, returns -1.  Throws IllegalArgumentException if
   2173          * neither incoming nor local class descriptor contains a match.
   2174          */
   2175         private int getFieldOffset(String name, Class type) {
   2176             ObjectStreamField field = desc.getField(name, type);
   2177             if (field != null) {
   2178                 return field.getOffset();
   2179             } else if (desc.getLocalDesc().getField(name, type) != null) {
   2180                 return -1;
   2181             } else {
   2182                 throw new IllegalArgumentException("no such field " + name +
   2183                                                    " with type " + type);
   2184             }
   2185         }
   2186     }
   2187 
   2188     /**
   2189      * Prioritized list of callbacks to be performed once object graph has been
   2190      * completely deserialized.
   2191      */
   2192     private static class ValidationList {
   2193 
   2194         private static class Callback {
   2195             final ObjectInputValidation obj;
   2196             final int priority;
   2197             Callback next;
   2198             final AccessControlContext acc;
   2199 
   2200             Callback(ObjectInputValidation obj, int priority, Callback next,
   2201                 AccessControlContext acc)
   2202             {
   2203                 this.obj = obj;
   2204                 this.priority = priority;
   2205                 this.next = next;
   2206                 this.acc = acc;
   2207             }
   2208         }
   2209 
   2210         /** linked list of callbacks */
   2211         private Callback list;
   2212 
   2213         /**
   2214          * Creates new (empty) ValidationList.
   2215          */
   2216         ValidationList() {
   2217         }
   2218 
   2219         /**
   2220          * Registers callback.  Throws InvalidObjectException if callback
   2221          * object is null.
   2222          */
   2223         void register(ObjectInputValidation obj, int priority)
   2224             throws InvalidObjectException
   2225         {
   2226             if (obj == null) {
   2227                 throw new InvalidObjectException("null callback");
   2228             }
   2229 
   2230             Callback prev = null, cur = list;
   2231             while (cur != null && priority < cur.priority) {
   2232                 prev = cur;
   2233                 cur = cur.next;
   2234             }
   2235             AccessControlContext acc = AccessController.getContext();
   2236             if (prev != null) {
   2237                 prev.next = new Callback(obj, priority, cur, acc);
   2238             } else {
   2239                 list = new Callback(obj, priority, list, acc);
   2240             }
   2241         }
   2242 
   2243         /**
   2244          * Invokes all registered callbacks and clears the callback list.
   2245          * Callbacks with higher priorities are called first; those with equal
   2246          * priorities may be called in any order.  If any of the callbacks
   2247          * throws an InvalidObjectException, the callback process is terminated
   2248          * and the exception propagated upwards.
   2249          */
   2250         void doCallbacks() throws InvalidObjectException {
   2251             try {
   2252                 while (list != null) {
   2253                     AccessController.doPrivileged(
   2254                         new PrivilegedExceptionAction<Void>()
   2255                     {
   2256                         public Void run() throws InvalidObjectException {
   2257                             list.obj.validateObject();
   2258                             return null;
   2259                         }
   2260                     }, list.acc);
   2261                     list = list.next;
   2262                 }
   2263             } catch (PrivilegedActionException ex) {
   2264                 list = null;
   2265                 throw (InvalidObjectException) ex.getException();
   2266             }
   2267         }
   2268 
   2269         /**
   2270          * Resets the callback list to its initial (empty) state.
   2271          */
   2272         public void clear() {
   2273             list = null;
   2274         }
   2275     }
   2276 
   2277     /**
   2278      * Input stream supporting single-byte peek operations.
   2279      */
   2280     private static class PeekInputStream extends InputStream {
   2281 
   2282         /** underlying stream */
   2283         private final InputStream in;
   2284         /** peeked byte */
   2285         private int peekb = -1;
   2286 
   2287         /**
   2288          * Creates new PeekInputStream on top of given underlying stream.
   2289          */
   2290         PeekInputStream(InputStream in) {
   2291             this.in = in;
   2292         }
   2293 
   2294         /**
   2295          * Peeks at next byte value in stream.  Similar to read(), except
   2296          * that it does not consume the read value.
   2297          */
   2298         int peek() throws IOException {
   2299             return (peekb >= 0) ? peekb : (peekb = in.read());
   2300         }
   2301 
   2302         public int read() throws IOException {
   2303             if (peekb >= 0) {
   2304                 int v = peekb;
   2305                 peekb = -1;
   2306                 return v;
   2307             } else {
   2308                 return in.read();
   2309             }
   2310         }
   2311 
   2312         public int read(byte[] b, int off, int len) throws IOException {
   2313             if (len == 0) {
   2314                 return 0;
   2315             } else if (peekb < 0) {
   2316                 return in.read(b, off, len);
   2317             } else {
   2318                 b[off++] = (byte) peekb;
   2319                 len--;
   2320                 peekb = -1;
   2321                 int n = in.read(b, off, len);
   2322                 return (n >= 0) ? (n + 1) : 1;
   2323             }
   2324         }
   2325 
   2326         void readFully(byte[] b, int off, int len) throws IOException {
   2327             int n = 0;
   2328             while (n < len) {
   2329                 int count = read(b, off + n, len - n);
   2330                 if (count < 0) {
   2331                     throw new EOFException();
   2332                 }
   2333                 n += count;
   2334             }
   2335         }
   2336 
   2337         public long skip(long n) throws IOException {
   2338             if (n <= 0) {
   2339                 return 0;
   2340             }
   2341             int skipped = 0;
   2342             if (peekb >= 0) {
   2343                 peekb = -1;
   2344                 skipped++;
   2345                 n--;
   2346             }
   2347             return skipped + skip(n);
   2348         }
   2349 
   2350         public int available() throws IOException {
   2351             return in.available() + ((peekb >= 0) ? 1 : 0);
   2352         }
   2353 
   2354         public void close() throws IOException {
   2355             in.close();
   2356         }
   2357     }
   2358 
   2359     /**
   2360      * Input stream with two modes: in default mode, inputs data written in the
   2361      * same format as DataOutputStream; in "block data" mode, inputs data
   2362      * bracketed by block data markers (see object serialization specification
   2363      * for details).  Buffering depends on block data mode: when in default
   2364      * mode, no data is buffered in advance; when in block data mode, all data
   2365      * for the current data block is read in at once (and buffered).
   2366      */
   2367     private class BlockDataInputStream
   2368         extends InputStream implements DataInput
   2369     {
   2370         /** maximum data block length */
   2371         private static final int MAX_BLOCK_SIZE = 1024;
   2372         /** maximum data block header length */
   2373         private static final int MAX_HEADER_SIZE = 5;
   2374         /** (tunable) length of char buffer (for reading strings) */
   2375         private static final int CHAR_BUF_SIZE = 256;
   2376         /** readBlockHeader() return value indicating header read may block */
   2377         private static final int HEADER_BLOCKED = -2;
   2378 
   2379         /** buffer for reading general/block data */
   2380         private final byte[] buf = new byte[MAX_BLOCK_SIZE];
   2381         /** buffer for reading block data headers */
   2382         private final byte[] hbuf = new byte[MAX_HEADER_SIZE];
   2383         /** char buffer for fast string reads */
   2384         private final char[] cbuf = new char[CHAR_BUF_SIZE];
   2385 
   2386         /** block data mode */
   2387         private boolean blkmode = false;
   2388 
   2389         // block data state fields; values meaningful only when blkmode true
   2390         /** current offset into buf */
   2391         private int pos = 0;
   2392         /** end offset of valid data in buf, or -1 if no more block data */
   2393         private int end = -1;
   2394         /** number of bytes in current block yet to be read from stream */
   2395         private int unread = 0;
   2396 
   2397         /** underlying stream (wrapped in peekable filter stream) */
   2398         private final PeekInputStream in;
   2399         /** loopback stream (for data reads that span data blocks) */
   2400         private final DataInputStream din;
   2401 
   2402         /**
   2403          * Creates new BlockDataInputStream on top of given underlying stream.
   2404          * Block data mode is turned off by default.
   2405          */
   2406         BlockDataInputStream(InputStream in) {
   2407             this.in = new PeekInputStream(in);
   2408             din = new DataInputStream(this);
   2409         }
   2410 
   2411         /**
   2412          * Sets block data mode to the given mode (true == on, false == off)
   2413          * and returns the previous mode value.  If the new mode is the same as
   2414          * the old mode, no action is taken.  Throws IllegalStateException if
   2415          * block data mode is being switched from on to off while unconsumed
   2416          * block data is still present in the stream.
   2417          */
   2418         boolean setBlockDataMode(boolean newmode) throws IOException {
   2419             if (blkmode == newmode) {
   2420                 return blkmode;
   2421             }
   2422             if (newmode) {
   2423                 pos = 0;
   2424                 end = 0;
   2425                 unread = 0;
   2426             } else if (pos < end) {
   2427                 throw new IllegalStateException("unread block data");
   2428             }
   2429             blkmode = newmode;
   2430             return !blkmode;
   2431         }
   2432 
   2433         /**
   2434          * Returns true if the stream is currently in block data mode, false
   2435          * otherwise.
   2436          */
   2437         boolean getBlockDataMode() {
   2438             return blkmode;
   2439         }
   2440 
   2441         /**
   2442          * If in block data mode, skips to the end of the current group of data
   2443          * blocks (but does not unset block data mode).  If not in block data
   2444          * mode, throws an IllegalStateException.
   2445          */
   2446         void skipBlockData() throws IOException {
   2447             if (!blkmode) {
   2448                 throw new IllegalStateException("not in block data mode");
   2449             }
   2450             while (end >= 0) {
   2451                 refill();
   2452             }
   2453         }
   2454 
   2455         /**
   2456          * Attempts to read in the next block data header (if any).  If
   2457          * canBlock is false and a full header cannot be read without possibly
   2458          * blocking, returns HEADER_BLOCKED, else if the next element in the
   2459          * stream is a block data header, returns the block data length
   2460          * specified by the header, else returns -1.
   2461          */
   2462         private int readBlockHeader(boolean canBlock) throws IOException {
   2463             if (defaultDataEnd) {
   2464                 /*
   2465                  * Fix for 4360508: stream is currently at the end of a field
   2466                  * value block written via default serialization; since there
   2467                  * is no terminating TC_ENDBLOCKDATA tag, simulate
   2468                  * end-of-custom-data behavior explicitly.
   2469                  */
   2470                 return -1;
   2471             }
   2472             try {
   2473                 for (;;) {
   2474                     int avail = canBlock ? Integer.MAX_VALUE : in.available();
   2475                     if (avail == 0) {
   2476                         return HEADER_BLOCKED;
   2477                     }
   2478 
   2479                     int tc = in.peek();
   2480                     switch (tc) {
   2481                         case TC_BLOCKDATA:
   2482                             if (avail < 2) {
   2483                                 return HEADER_BLOCKED;
   2484                             }
   2485                             in.readFully(hbuf, 0, 2);
   2486                             return hbuf[1] & 0xFF;
   2487 
   2488                         case TC_BLOCKDATALONG:
   2489                             if (avail < 5) {
   2490                                 return HEADER_BLOCKED;
   2491                             }
   2492                             in.readFully(hbuf, 0, 5);
   2493                             int len = Bits.getInt(hbuf, 1);
   2494                             if (len < 0) {
   2495                                 throw new StreamCorruptedException(
   2496                                     "illegal block data header length: " +
   2497                                     len);
   2498                             }
   2499                             return len;
   2500 
   2501                         /*
   2502                          * TC_RESETs may occur in between data blocks.
   2503                          * Unfortunately, this case must be parsed at a lower
   2504                          * level than other typecodes, since primitive data
   2505                          * reads may span data blocks separated by a TC_RESET.
   2506                          */
   2507                         case TC_RESET:
   2508                             in.read();
   2509                             handleReset();
   2510                             break;
   2511 
   2512                         default:
   2513                             if (tc >= 0 && (tc < TC_BASE || tc > TC_MAX)) {
   2514                                 throw new StreamCorruptedException(
   2515                                     String.format("invalid type code: %02X",
   2516                                     tc));
   2517                             }
   2518                             return -1;
   2519                     }
   2520                 }
   2521             } catch (EOFException ex) {
   2522                 throw new StreamCorruptedException(
   2523                     "unexpected EOF while reading block data header");
   2524             }
   2525         }
   2526 
   2527         /**
   2528          * Refills internal buffer buf with block data.  Any data in buf at the
   2529          * time of the call is considered consumed.  Sets the pos, end, and
   2530          * unread fields to reflect the new amount of available block data; if
   2531          * the next element in the stream is not a data block, sets pos and
   2532          * unread to 0 and end to -1.
   2533          */
   2534         private void refill() throws IOException {
   2535             try {
   2536                 do {
   2537                     pos = 0;
   2538                     if (unread > 0) {
   2539                         int n =
   2540                             in.read(buf, 0, Math.min(unread, MAX_BLOCK_SIZE));
   2541                         if (n >= 0) {
   2542                             end = n;
   2543                             unread -= n;
   2544                         } else {
   2545                             throw new StreamCorruptedException(
   2546                                 "unexpected EOF in middle of data block");
   2547                         }
   2548                     } else {
   2549                         int n = readBlockHeader(true);
   2550                         if (n >= 0) {
   2551                             end = 0;
   2552                             unread = n;
   2553                         } else {
   2554                             end = -1;
   2555                             unread = 0;
   2556                         }
   2557                     }
   2558                 } while (pos == end);
   2559             } catch (IOException ex) {
   2560                 pos = 0;
   2561                 end = -1;
   2562                 unread = 0;
   2563                 throw ex;
   2564             }
   2565         }
   2566 
   2567         /**
   2568          * If in block data mode, returns the number of unconsumed bytes
   2569          * remaining in the current data block.  If not in block data mode,
   2570          * throws an IllegalStateException.
   2571          */
   2572         int currentBlockRemaining() {
   2573             if (blkmode) {
   2574                 return (end >= 0) ? (end - pos) + unread : 0;
   2575             } else {
   2576                 throw new IllegalStateException();
   2577             }
   2578         }
   2579 
   2580         /**
   2581          * Peeks at (but does not consume) and returns the next byte value in
   2582          * the stream, or -1 if the end of the stream/block data (if in block
   2583          * data mode) has been reached.
   2584          */
   2585         int peek() 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.peek();
   2593             }
   2594         }
   2595 
   2596         /**
   2597          * Peeks at (but does not consume) and returns the next byte value in
   2598          * the stream, or throws EOFException if end of stream/block data has
   2599          * been reached.
   2600          */
   2601         byte peekByte() throws IOException {
   2602             int val = peek();
   2603             if (val < 0) {
   2604                 throw new EOFException();
   2605             }
   2606             return (byte) val;
   2607         }
   2608 
   2609 
   2610         /* ----------------- generic input stream methods ------------------ */
   2611         /*
   2612          * The following methods are equivalent to their counterparts in
   2613          * InputStream, except that they interpret data block boundaries and
   2614          * read the requested data from within data blocks when in block data
   2615          * mode.
   2616          */
   2617 
   2618         public int read() throws IOException {
   2619             if (blkmode) {
   2620                 if (pos == end) {
   2621                     refill();
   2622                 }
   2623                 return (end >= 0) ? (buf[pos++] & 0xFF) : -1;
   2624             } else {
   2625                 return in.read();
   2626             }
   2627         }
   2628 
   2629         public int read(byte[] b, int off, int len) throws IOException {
   2630             return read(b, off, len, false);
   2631         }
   2632 
   2633         public long skip(long len) throws IOException {
   2634             long remain = len;
   2635             while (remain > 0) {
   2636                 if (blkmode) {
   2637                     if (pos == end) {
   2638                         refill();
   2639                     }
   2640                     if (end < 0) {
   2641                         break;
   2642                     }
   2643                     int nread = (int) Math.min(remain, end - pos);
   2644                     remain -= nread;
   2645                     pos += nread;
   2646                 } else {
   2647                     int nread = (int) Math.min(remain, MAX_BLOCK_SIZE);
   2648                     if ((nread = in.read(buf, 0, nread)) < 0) {
   2649                         break;
   2650                     }
   2651                     remain -= nread;
   2652                 }
   2653             }
   2654             return len - remain;
   2655         }
   2656 
   2657         public int available() throws IOException {
   2658             if (blkmode) {
   2659                 if ((pos == end) && (unread == 0)) {
   2660                     int n;
   2661                     while ((n = readBlockHeader(false)) == 0) ;
   2662                     switch (n) {
   2663                         case HEADER_BLOCKED:
   2664                             break;
   2665 
   2666                         case -1:
   2667                             pos = 0;
   2668                             end = -1;
   2669                             break;
   2670 
   2671                         default:
   2672                             pos = 0;
   2673                             end = 0;
   2674                             unread = n;
   2675                             break;
   2676                     }
   2677                 }
   2678                 // avoid unnecessary call to in.available() if possible
   2679                 int unreadAvail = (unread > 0) ?
   2680                     Math.min(in.available(), unread) : 0;
   2681                 return (end >= 0) ? (end - pos) + unreadAvail : 0;
   2682             } else {
   2683                 return in.available();
   2684             }
   2685         }
   2686 
   2687         public void close() throws IOException {
   2688             if (blkmode) {
   2689                 pos = 0;
   2690                 end = -1;
   2691                 unread = 0;
   2692             }
   2693             in.close();
   2694         }
   2695 
   2696         /**
   2697          * Attempts to read len bytes into byte array b at offset off.  Returns
   2698          * the number of bytes read, or -1 if the end of stream/block data has
   2699          * been reached.  If copy is true, reads values into an intermediate
   2700          * buffer before copying them to b (to avoid exposing a reference to
   2701          * b).
   2702          */
   2703         int read(byte[] b, int off, int len, boolean copy) throws IOException {
   2704             if (len == 0) {
   2705                 return 0;
   2706             } else if (blkmode) {
   2707                 if (pos == end) {
   2708                     refill();
   2709                 }
   2710                 if (end < 0) {
   2711                     return -1;
   2712                 }
   2713                 int nread = Math.min(len, end - pos);
   2714                 System.arraycopy(buf, pos, b, off, nread);
   2715                 pos += nread;
   2716                 return nread;
   2717             } else if (copy) {
   2718                 int nread = in.read(buf, 0, Math.min(len, MAX_BLOCK_SIZE));
   2719                 if (nread > 0) {
   2720                     System.arraycopy(buf, 0, b, off, nread);
   2721                 }
   2722                 return nread;
   2723             } else {
   2724                 return in.read(b, off, len);
   2725             }
   2726         }
   2727 
   2728         /* ----------------- primitive data input methods ------------------ */
   2729         /*
   2730          * The following methods are equivalent to their counterparts in
   2731          * DataInputStream, except that they interpret data block boundaries
   2732          * and read the requested data from within data blocks when in block
   2733          * data mode.
   2734          */
   2735 
   2736         public void readFully(byte[] b) throws IOException {
   2737             readFully(b, 0, b.length, false);
   2738         }
   2739 
   2740         public void readFully(byte[] b, int off, int len) throws IOException {
   2741             readFully(b, off, len, false);
   2742         }
   2743 
   2744         public void readFully(byte[] b, int off, int len, boolean copy)
   2745             throws IOException
   2746         {
   2747             while (len > 0) {
   2748                 int n = read(b, off, len, copy);
   2749                 if (n < 0) {
   2750                     throw new EOFException();
   2751                 }
   2752                 off += n;
   2753                 len -= n;
   2754             }
   2755         }
   2756 
   2757         public int skipBytes(int n) throws IOException {
   2758             return din.skipBytes(n);
   2759         }
   2760 
   2761         public boolean readBoolean() throws IOException {
   2762             int v = read();
   2763             if (v < 0) {
   2764                 throw new EOFException();
   2765             }
   2766             return (v != 0);
   2767         }
   2768 
   2769         public byte readByte() throws IOException {
   2770             int v = read();
   2771             if (v < 0) {
   2772                 throw new EOFException();
   2773             }
   2774             return (byte) v;
   2775         }
   2776 
   2777         public int readUnsignedByte() throws IOException {
   2778             int v = read();
   2779             if (v < 0) {
   2780                 throw new EOFException();
   2781             }
   2782             return v;
   2783         }
   2784 
   2785         public char readChar() throws IOException {
   2786             if (!blkmode) {
   2787                 pos = 0;
   2788                 in.readFully(buf, 0, 2);
   2789             } else if (end - pos < 2) {
   2790                 return din.readChar();
   2791             }
   2792             char v = Bits.getChar(buf, pos);
   2793             pos += 2;
   2794             return v;
   2795         }
   2796 
   2797         public short readShort() throws IOException {
   2798             if (!blkmode) {
   2799                 pos = 0;
   2800                 in.readFully(buf, 0, 2);
   2801             } else if (end - pos < 2) {
   2802                 return din.readShort();
   2803             }
   2804             short v = Bits.getShort(buf, pos);
   2805             pos += 2;
   2806             return v;
   2807         }
   2808 
   2809         public int readUnsignedShort() throws IOException {
   2810             if (!blkmode) {
   2811                 pos = 0;
   2812                 in.readFully(buf, 0, 2);
   2813             } else if (end - pos < 2) {
   2814                 return din.readUnsignedShort();
   2815             }
   2816             int v = Bits.getShort(buf, pos) & 0xFFFF;
   2817             pos += 2;
   2818             return v;
   2819         }
   2820 
   2821         public int readInt() throws IOException {
   2822             if (!blkmode) {
   2823                 pos = 0;
   2824                 in.readFully(buf, 0, 4);
   2825             } else if (end - pos < 4) {
   2826                 return din.readInt();
   2827             }
   2828             int v = Bits.getInt(buf, pos);
   2829             pos += 4;
   2830             return v;
   2831         }
   2832 
   2833         public float readFloat() throws IOException {
   2834             if (!blkmode) {
   2835                 pos = 0;
   2836                 in.readFully(buf, 0, 4);
   2837             } else if (end - pos < 4) {
   2838                 return din.readFloat();
   2839             }
   2840             float v = Bits.getFloat(buf, pos);
   2841             pos += 4;
   2842             return v;
   2843         }
   2844 
   2845         public long readLong() throws IOException {
   2846             if (!blkmode) {
   2847                 pos = 0;
   2848                 in.readFully(buf, 0, 8);
   2849             } else if (end - pos < 8) {
   2850                 return din.readLong();
   2851             }
   2852             long v = Bits.getLong(buf, pos);
   2853             pos += 8;
   2854             return v;
   2855         }
   2856 
   2857         public double readDouble() throws IOException {
   2858             if (!blkmode) {
   2859                 pos = 0;
   2860                 in.readFully(buf, 0, 8);
   2861             } else if (end - pos < 8) {
   2862                 return din.readDouble();
   2863             }
   2864             double v = Bits.getDouble(buf, pos);
   2865             pos += 8;
   2866             return v;
   2867         }
   2868 
   2869         public String readUTF() throws IOException {
   2870             return readUTFBody(readUnsignedShort());
   2871         }
   2872 
   2873         public String readLine() throws IOException {
   2874             return din.readLine();      // deprecated, not worth optimizing
   2875         }
   2876 
   2877         /* -------------- primitive data array input methods --------------- */
   2878         /*
   2879          * The following methods read in spans of primitive data values.
   2880          * Though equivalent to calling the corresponding primitive read
   2881          * methods repeatedly, these methods are optimized for reading groups
   2882          * of primitive data values more efficiently.
   2883          */
   2884 
   2885         void readBooleans(boolean[] v, int off, int len) throws IOException {
   2886             int stop, endoff = off + len;
   2887             while (off < endoff) {
   2888                 if (!blkmode) {
   2889                     int span = Math.min(endoff - off, MAX_BLOCK_SIZE);
   2890                     in.readFully(buf, 0, span);
   2891                     stop = off + span;
   2892                     pos = 0;
   2893                 } else if (end - pos < 1) {
   2894                     v[off++] = din.readBoolean();
   2895                     continue;
   2896                 } else {
   2897                     stop = Math.min(endoff, off + end - pos);
   2898                 }
   2899 
   2900                 while (off < stop) {
   2901                     v[off++] = Bits.getBoolean(buf, pos++);
   2902                 }
   2903             }
   2904         }
   2905 
   2906         void readChars(char[] v, int off, int len) throws IOException {
   2907             int stop, endoff = off + len;
   2908             while (off < endoff) {
   2909                 if (!blkmode) {
   2910                     int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 1);
   2911                     in.readFully(buf, 0, span << 1);
   2912                     stop = off + span;
   2913                     pos = 0;
   2914                 } else if (end - pos < 2) {
   2915                     v[off++] = din.readChar();
   2916                     continue;
   2917                 } else {
   2918                     stop = Math.min(endoff, off + ((end - pos) >> 1));
   2919                 }
   2920 
   2921                 while (off < stop) {
   2922                     v[off++] = Bits.getChar(buf, pos);
   2923                     pos += 2;
   2924                 }
   2925             }
   2926         }
   2927 
   2928         void readShorts(short[] v, int off, int len) throws IOException {
   2929             int stop, endoff = off + len;
   2930             while (off < endoff) {
   2931                 if (!blkmode) {
   2932                     int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 1);
   2933                     in.readFully(buf, 0, span << 1);
   2934                     stop = off + span;
   2935                     pos = 0;
   2936                 } else if (end - pos < 2) {
   2937                     v[off++] = din.readShort();
   2938                     continue;
   2939                 } else {
   2940                     stop = Math.min(endoff, off + ((end - pos) >> 1));
   2941                 }
   2942 
   2943                 while (off < stop) {
   2944                     v[off++] = Bits.getShort(buf, pos);
   2945                     pos += 2;
   2946                 }
   2947             }
   2948         }
   2949 
   2950         void readInts(int[] v, int off, int len) throws IOException {
   2951             int stop, endoff = off + len;
   2952             while (off < endoff) {
   2953                 if (!blkmode) {
   2954                     int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 2);
   2955                     in.readFully(buf, 0, span << 2);
   2956                     stop = off + span;
   2957                     pos = 0;
   2958                 } else if (end - pos < 4) {
   2959                     v[off++] = din.readInt();
   2960                     continue;
   2961                 } else {
   2962                     stop = Math.min(endoff, off + ((end - pos) >> 2));
   2963                 }
   2964 
   2965                 while (off < stop) {
   2966                     v[off++] = Bits.getInt(buf, pos);
   2967                     pos += 4;
   2968                 }
   2969             }
   2970         }
   2971 
   2972         void readFloats(float[] v, int off, int len) throws IOException {
   2973             int span, endoff = off + len;
   2974             while (off < endoff) {
   2975                 if (!blkmode) {
   2976                     span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 2);
   2977                     in.readFully(buf, 0, span << 2);
   2978                     pos = 0;
   2979                 } else if (end - pos < 4) {
   2980                     v[off++] = din.readFloat();
   2981                     continue;
   2982                 } else {
   2983                     span = Math.min(endoff - off, ((end - pos) >> 2));
   2984                 }
   2985 
   2986                 bytesToFloats(buf, pos, v, off, span);
   2987                 off += span;
   2988                 pos += span << 2;
   2989             }
   2990         }
   2991 
   2992         void readLongs(long[] v, int off, int len) throws IOException {
   2993             int stop, endoff = off + len;
   2994             while (off < endoff) {
   2995                 if (!blkmode) {
   2996                     int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 3);
   2997                     in.readFully(buf, 0, span << 3);
   2998                     stop = off + span;
   2999                     pos = 0;
   3000                 } else if (end - pos < 8) {
   3001                     v[off++] = din.readLong();
   3002                     continue;
   3003                 } else {
   3004                     stop = Math.min(endoff, off + ((end - pos) >> 3));
   3005                 }
   3006 
   3007                 while (off < stop) {
   3008                     v[off++] = Bits.getLong(buf, pos);
   3009                     pos += 8;
   3010                 }
   3011             }
   3012         }
   3013 
   3014         void readDoubles(double[] v, int off, int len) throws IOException {
   3015             int span, endoff = off + len;
   3016             while (off < endoff) {
   3017                 if (!blkmode) {
   3018                     span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 3);
   3019                     in.readFully(buf, 0, span << 3);
   3020                     pos = 0;
   3021                 } else if (end - pos < 8) {
   3022                     v[off++] = din.readDouble();
   3023                     continue;
   3024                 } else {
   3025                     span = Math.min(endoff - off, ((end - pos) >> 3));
   3026                 }
   3027 
   3028                 bytesToDoubles(buf, pos, v, off, span);
   3029                 off += span;
   3030                 pos += span << 3;
   3031             }
   3032         }
   3033 
   3034         /**
   3035          * Reads in string written in "long" UTF format.  "Long" UTF format is
   3036          * identical to standard UTF, except that it uses an 8 byte header
   3037          * (instead of the standard 2 bytes) to convey the UTF encoding length.
   3038          */
   3039         String readLongUTF() throws IOException {
   3040             return readUTFBody(readLong());
   3041         }
   3042 
   3043         /**
   3044          * Reads in the "body" (i.e., the UTF representation minus the 2-byte
   3045          * or 8-byte length header) of a UTF encoding, which occupies the next
   3046          * utflen bytes.
   3047          */
   3048         private String readUTFBody(long utflen) throws IOException {
   3049             StringBuilder sbuf = new StringBuilder();
   3050             if (!blkmode) {
   3051                 end = pos = 0;
   3052             }
   3053 
   3054             while (utflen > 0) {
   3055                 int avail = end - pos;
   3056                 if (avail >= 3 || (long) avail == utflen) {
   3057                     utflen -= readUTFSpan(sbuf, utflen);
   3058                 } else {
   3059                     if (blkmode) {
   3060                         // near block boundary, read one byte at a time
   3061                         utflen -= readUTFChar(sbuf, utflen);
   3062                     } else {
   3063                         // shift and refill buffer manually
   3064                         if (avail > 0) {
   3065                             System.arraycopy(buf, pos, buf, 0, avail);
   3066                         }
   3067                         pos = 0;
   3068                         end = (int) Math.min(MAX_BLOCK_SIZE, utflen);
   3069                         in.readFully(buf, avail, end - avail);
   3070                     }
   3071                 }
   3072             }
   3073 
   3074             return sbuf.toString();
   3075         }
   3076 
   3077         /**
   3078          * Reads span of UTF-encoded characters out of internal buffer
   3079          * (starting at offset pos and ending at or before offset end),
   3080          * consuming no more than utflen bytes.  Appends read characters to
   3081          * sbuf.  Returns the number of bytes consumed.
   3082          */
   3083         private long readUTFSpan(StringBuilder sbuf, long utflen)
   3084             throws IOException
   3085         {
   3086             int cpos = 0;
   3087             int start = pos;
   3088             int avail = Math.min(end - pos, CHAR_BUF_SIZE);
   3089             // stop short of last char unless all of utf bytes in buffer
   3090             int stop = pos + ((utflen > avail) ? avail - 2 : (int) utflen);
   3091             boolean outOfBounds = false;
   3092 
   3093             try {
   3094                 while (pos < stop) {
   3095                     int b1, b2, b3;
   3096                     b1 = buf[pos++] & 0xFF;
   3097                     switch (b1 >> 4) {
   3098                         case 0:
   3099                         case 1:
   3100                         case 2:
   3101                         case 3:
   3102                         case 4:
   3103                         case 5:
   3104                         case 6:
   3105                         case 7:   // 1 byte format: 0xxxxxxx
   3106                             cbuf[cpos++] = (char) b1;
   3107                             break;
   3108 
   3109                         case 12:
   3110                         case 13:  // 2 byte format: 110xxxxx 10xxxxxx
   3111                             b2 = buf[pos++];
   3112                             if ((b2 & 0xC0) != 0x80) {
   3113                                 throw new UTFDataFormatException();
   3114                             }
   3115                             cbuf[cpos++] = (char) (((b1 & 0x1F) << 6) |
   3116                                                    ((b2 & 0x3F) << 0));
   3117                             break;
   3118 
   3119                         case 14:  // 3 byte format: 1110xxxx 10xxxxxx 10xxxxxx
   3120                             b3 = buf[pos + 1];
   3121                             b2 = buf[pos + 0];
   3122                             pos += 2;
   3123                             if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) {
   3124                                 throw new UTFDataFormatException();
   3125                             }
   3126                             cbuf[cpos++] = (char) (((b1 & 0x0F) << 12) |
   3127                                                    ((b2 & 0x3F) << 6) |
   3128                                                    ((b3 & 0x3F) << 0));
   3129                             break;
   3130 
   3131                         default:  // 10xx xxxx, 1111 xxxx
   3132                             throw new UTFDataFormatException();
   3133                     }
   3134                 }
   3135             } catch (ArrayIndexOutOfBoundsException ex) {
   3136                 outOfBounds = true;
   3137             } finally {
   3138                 if (outOfBounds || (pos - start) > utflen) {
   3139                     /*
   3140                      * Fix for 4450867: if a malformed utf char causes the
   3141                      * conversion loop to scan past the expected end of the utf
   3142                      * string, only consume the expected number of utf bytes.
   3143                      */
   3144                     pos = start + (int) utflen;
   3145                     throw new UTFDataFormatException();
   3146                 }
   3147             }
   3148 
   3149             sbuf.append(cbuf, 0, cpos);
   3150             return pos - start;
   3151         }
   3152 
   3153         /**
   3154          * Reads in single UTF-encoded character one byte at a time, appends
   3155          * the character to sbuf, and returns the number of bytes consumed.
   3156          * This method is used when reading in UTF strings written in block
   3157          * data mode to handle UTF-encoded characters which (potentially)
   3158          * straddle block-data boundaries.
   3159          */
   3160         private int readUTFChar(StringBuilder sbuf, long utflen)
   3161             throws IOException
   3162         {
   3163             int b1, b2, b3;
   3164             b1 = readByte() & 0xFF;
   3165             switch (b1 >> 4) {
   3166                 case 0:
   3167                 case 1:
   3168                 case 2:
   3169                 case 3:
   3170                 case 4:
   3171                 case 5:
   3172                 case 6:
   3173                 case 7:     // 1 byte format: 0xxxxxxx
   3174                     sbuf.append((char) b1);
   3175                     return 1;
   3176 
   3177                 case 12:
   3178                 case 13:    // 2 byte format: 110xxxxx 10xxxxxx
   3179                     if (utflen < 2) {
   3180                         throw new UTFDataFormatException();
   3181                     }
   3182                     b2 = readByte();
   3183                     if ((b2 & 0xC0) != 0x80) {
   3184                         throw new UTFDataFormatException();
   3185                     }
   3186                     sbuf.append((char) (((b1 & 0x1F) << 6) |
   3187                                         ((b2 & 0x3F) << 0)));
   3188                     return 2;
   3189 
   3190                 case 14:    // 3 byte format: 1110xxxx 10xxxxxx 10xxxxxx
   3191                     if (utflen < 3) {
   3192                         if (utflen == 2) {
   3193                             readByte();         // consume remaining byte
   3194                         }
   3195                         throw new UTFDataFormatException();
   3196                     }
   3197                     b2 = readByte();
   3198                     b3 = readByte();
   3199                     if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) {
   3200                         throw new UTFDataFormatException();
   3201                     }
   3202                     sbuf.append((char) (((b1 & 0x0F) << 12) |
   3203                                         ((b2 & 0x3F) << 6) |
   3204                                         ((b3 & 0x3F) << 0)));
   3205                     return 3;
   3206 
   3207                 default:   // 10xx xxxx, 1111 xxxx
   3208                     throw new UTFDataFormatException();
   3209             }
   3210         }
   3211     }
   3212 
   3213     /**
   3214      * Unsynchronized table which tracks wire handle to object mappings, as
   3215      * well as ClassNotFoundExceptions associated with deserialized objects.
   3216      * This class implements an exception-propagation algorithm for
   3217      * determining which objects should have ClassNotFoundExceptions associated
   3218      * with them, taking into account cycles and discontinuities (e.g., skipped
   3219      * fields) in the object graph.
   3220      *
   3221      * <p>General use of the table is as follows: during deserialization, a
   3222      * given object is first assigned a handle by calling the assign method.
   3223      * This method leaves the assigned handle in an "open" state, wherein
   3224      * dependencies on the exception status of other handles can be registered
   3225      * by calling the markDependency method, or an exception can be directly
   3226      * associated with the handle by calling markException.  When a handle is
   3227      * tagged with an exception, the HandleTable assumes responsibility for
   3228      * propagating the exception to any other objects which depend
   3229      * (transitively) on the exception-tagged object.
   3230      *
   3231      * <p>Once all exception information/dependencies for the handle have been
   3232      * registered, the handle should be "closed" by calling the finish method
   3233      * on it.  The act of finishing a handle allows the exception propagation
   3234      * algorithm to aggressively prune dependency links, lessening the
   3235      * performance/memory impact of exception tracking.
   3236      *
   3237      * <p>Note that the exception propagation algorithm used depends on handles
   3238      * being assigned/finished in LIFO order; however, for simplicity as well
   3239      * as memory conservation, it does not enforce this constraint.
   3240      */
   3241     // REMIND: add full description of exception propagation algorithm?
   3242     private static class HandleTable {
   3243 
   3244         /* status codes indicating whether object has associated exception */
   3245         private static final byte STATUS_OK = 1;
   3246         private static final byte STATUS_UNKNOWN = 2;
   3247         private static final byte STATUS_EXCEPTION = 3;
   3248 
   3249         /** array mapping handle -> object status */
   3250         byte[] status;
   3251         /** array mapping handle -> object/exception (depending on status) */
   3252         Object[] entries;
   3253         /** array mapping handle -> list of dependent handles (if any) */
   3254         HandleList[] deps;
   3255         /** lowest unresolved dependency */
   3256         int lowDep = -1;
   3257         /** number of handles in table */
   3258         int size = 0;
   3259 
   3260         /**
   3261          * Creates handle table with the given initial capacity.
   3262          */
   3263         HandleTable(int initialCapacity) {
   3264             status = new byte[initialCapacity];
   3265             entries = new Object[initialCapacity];
   3266             deps = new HandleList[initialCapacity];
   3267         }
   3268 
   3269         /**
   3270          * Assigns next available handle to given object, and returns assigned
   3271          * handle.  Once object has been completely deserialized (and all
   3272          * dependencies on other objects identified), the handle should be
   3273          * "closed" by passing it to finish().
   3274          */
   3275         int assign(Object obj) {
   3276             if (size >= entries.length) {
   3277                 grow();
   3278             }
   3279             status[size] = STATUS_UNKNOWN;
   3280             entries[size] = obj;
   3281             return size++;
   3282         }
   3283 
   3284         /**
   3285          * Registers a dependency (in exception status) of one handle on
   3286          * another.  The dependent handle must be "open" (i.e., assigned, but
   3287          * not finished yet).  No action is taken if either dependent or target
   3288          * handle is NULL_HANDLE.
   3289          */
   3290         void markDependency(int dependent, int target) {
   3291             if (dependent == NULL_HANDLE || target == NULL_HANDLE) {
   3292                 return;
   3293             }
   3294             switch (status[dependent]) {
   3295 
   3296                 case STATUS_UNKNOWN:
   3297                     switch (status[target]) {
   3298                         case STATUS_OK:
   3299                             // ignore dependencies on objs with no exception
   3300                             break;
   3301 
   3302                         case STATUS_EXCEPTION:
   3303                             // eagerly propagate exception
   3304                             markException(dependent,
   3305                                 (ClassNotFoundException) entries[target]);
   3306                             break;
   3307 
   3308                         case STATUS_UNKNOWN:
   3309                             // add to dependency list of target
   3310                             if (deps[target] == null) {
   3311                                 deps[target] = new HandleList();
   3312                             }
   3313                             deps[target].add(dependent);
   3314 
   3315                             // remember lowest unresolved target seen
   3316                             if (lowDep < 0 || lowDep > target) {
   3317                                 lowDep = target;
   3318                             }
   3319                             break;
   3320 
   3321                         default:
   3322                             throw new InternalError();
   3323                     }
   3324                     break;
   3325 
   3326                 case STATUS_EXCEPTION:
   3327                     break;
   3328 
   3329                 default:
   3330                     throw new InternalError();
   3331             }
   3332         }
   3333 
   3334         /**
   3335          * Associates a ClassNotFoundException (if one not already associated)
   3336          * with the currently active handle and propagates it to other
   3337          * referencing objects as appropriate.  The specified handle must be
   3338          * "open" (i.e., assigned, but not finished yet).
   3339          */
   3340         void markException(int handle, ClassNotFoundException ex) {
   3341             switch (status[handle]) {
   3342                 case STATUS_UNKNOWN:
   3343                     status[handle] = STATUS_EXCEPTION;
   3344                     entries[handle] = ex;
   3345 
   3346                     // propagate exception to dependents
   3347                     HandleList dlist = deps[handle];
   3348                     if (dlist != null) {
   3349                         int ndeps = dlist.size();
   3350                         for (int i = 0; i < ndeps; i++) {
   3351                             markException(dlist.get(i), ex);
   3352                         }
   3353                         deps[handle] = null;
   3354                     }
   3355                     break;
   3356 
   3357                 case STATUS_EXCEPTION:
   3358                     break;
   3359 
   3360                 default:
   3361                     throw new InternalError();
   3362             }
   3363         }
   3364 
   3365         /**
   3366          * Marks given handle as finished, meaning that no new dependencies
   3367          * will be marked for handle.  Calls to the assign and finish methods
   3368          * must occur in LIFO order.
   3369          */
   3370         void finish(int handle) {
   3371             int end;
   3372             if (lowDep < 0) {
   3373                 // no pending unknowns, only resolve current handle
   3374                 end = handle + 1;
   3375             } else if (lowDep >= handle) {
   3376                 // pending unknowns now clearable, resolve all upward handles
   3377                 end = size;
   3378                 lowDep = -1;
   3379             } else {
   3380                 // unresolved backrefs present, can't resolve anything yet
   3381                 return;
   3382             }
   3383 
   3384             // change STATUS_UNKNOWN -> STATUS_OK in selected span of handles
   3385             for (int i = handle; i < end; i++) {
   3386                 switch (status[i]) {
   3387                     case STATUS_UNKNOWN:
   3388                         status[i] = STATUS_OK;
   3389                         deps[i] = null;
   3390                         break;
   3391 
   3392                     case STATUS_OK:
   3393                     case STATUS_EXCEPTION:
   3394                         break;
   3395 
   3396                     default:
   3397                         throw new InternalError();
   3398                 }
   3399             }
   3400         }
   3401 
   3402         /**
   3403          * Assigns a new object to the given handle.  The object previously
   3404          * associated with the handle is forgotten.  This method has no effect
   3405          * if the given handle already has an exception associated with it.
   3406          * This method may be called at any time after the handle is assigned.
   3407          */
   3408         void setObject(int handle, Object obj) {
   3409             switch (status[handle]) {
   3410                 case STATUS_UNKNOWN:
   3411                 case STATUS_OK:
   3412                     entries[handle] = obj;
   3413                     break;
   3414 
   3415                 case STATUS_EXCEPTION:
   3416                     break;
   3417 
   3418                 default:
   3419                     throw new InternalError();
   3420             }
   3421         }
   3422 
   3423         /**
   3424          * Looks up and returns object associated with the given handle.
   3425          * Returns null if the given handle is NULL_HANDLE, or if it has an
   3426          * associated ClassNotFoundException.
   3427          */
   3428         Object lookupObject(int handle) {
   3429             return (handle != NULL_HANDLE &&
   3430                     status[handle] != STATUS_EXCEPTION) ?
   3431                 entries[handle] : null;
   3432         }
   3433 
   3434         /**
   3435          * Looks up and returns ClassNotFoundException associated with the
   3436          * given handle.  Returns null if the given handle is NULL_HANDLE, or
   3437          * if there is no ClassNotFoundException associated with the handle.
   3438          */
   3439         ClassNotFoundException lookupException(int handle) {
   3440             return (handle != NULL_HANDLE &&
   3441                     status[handle] == STATUS_EXCEPTION) ?
   3442                 (ClassNotFoundException) entries[handle] : null;
   3443         }
   3444 
   3445         /**
   3446          * Resets table to its initial state.
   3447          */
   3448         void clear() {
   3449             Arrays.fill(status, 0, size, (byte) 0);
   3450             Arrays.fill(entries, 0, size, null);
   3451             Arrays.fill(deps, 0, size, null);
   3452             lowDep = -1;
   3453             size = 0;
   3454         }
   3455 
   3456         /**
   3457          * Returns number of handles registered in table.
   3458          */
   3459         int size() {
   3460             return size;
   3461         }
   3462 
   3463         /**
   3464          * Expands capacity of internal arrays.
   3465          */
   3466         private void grow() {
   3467             int newCapacity = (entries.length << 1) + 1;
   3468 
   3469             byte[] newStatus = new byte[newCapacity];
   3470             Object[] newEntries = new Object[newCapacity];
   3471             HandleList[] newDeps = new HandleList[newCapacity];
   3472 
   3473             System.arraycopy(status, 0, newStatus, 0, size);
   3474             System.arraycopy(entries, 0, newEntries, 0, size);
   3475             System.arraycopy(deps, 0, newDeps, 0, size);
   3476 
   3477             status = newStatus;
   3478             entries = newEntries;
   3479             deps = newDeps;
   3480         }
   3481 
   3482         /**
   3483          * Simple growable list of (integer) handles.
   3484          */
   3485         private static class HandleList {
   3486             private int[] list = new int[4];
   3487             private int size = 0;
   3488 
   3489             public HandleList() {
   3490             }
   3491 
   3492             public void add(int handle) {
   3493                 if (size >= list.length) {
   3494                     int[] newList = new int[list.length << 1];
   3495                     System.arraycopy(list, 0, newList, 0, list.length);
   3496                     list = newList;
   3497                 }
   3498                 list[size++] = handle;
   3499             }
   3500 
   3501             public int get(int index) {
   3502                 if (index >= size) {
   3503                     throw new ArrayIndexOutOfBoundsException();
   3504                 }
   3505                 return list[index];
   3506             }
   3507 
   3508             public int size() {
   3509                 return size;
   3510             }
   3511         }
   3512     }
   3513 
   3514     /**
   3515      * Method for cloning arrays in case of using unsharing reading
   3516      */
   3517     private static Object cloneArray(Object array) {
   3518         if (array instanceof Object[]) {
   3519             return ((Object[]) array).clone();
   3520         } else if (array instanceof boolean[]) {
   3521             return ((boolean[]) array).clone();
   3522         } else if (array instanceof byte[]) {
   3523             return ((byte[]) array).clone();
   3524         } else if (array instanceof char[]) {
   3525             return ((char[]) array).clone();
   3526         } else if (array instanceof double[]) {
   3527             return ((double[]) array).clone();
   3528         } else if (array instanceof float[]) {
   3529             return ((float[]) array).clone();
   3530         } else if (array instanceof int[]) {
   3531             return ((int[]) array).clone();
   3532         } else if (array instanceof long[]) {
   3533             return ((long[]) array).clone();
   3534         } else if (array instanceof short[]) {
   3535             return ((short[]) array).clone();
   3536         } else {
   3537             throw new AssertionError();
   3538         }
   3539     }
   3540 
   3541 }
   3542