Home » openjdk-7 » java » io » [javadoc | source]

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

Home » openjdk-7 » java » io » [javadoc | source]