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