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