rt/emul/compact/src/main/java/java/io/ObjectInputStream.java
changeset 772 d382dacfd73f
parent 604 3fcc279c921b
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/rt/emul/compact/src/main/java/java/io/ObjectInputStream.java	Tue Feb 26 16:54:16 2013 +0100
     1.3 @@ -0,0 +1,3357 @@
     1.4 +/*
     1.5 + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
     1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.7 + *
     1.8 + * This code is free software; you can redistribute it and/or modify it
     1.9 + * under the terms of the GNU General Public License version 2 only, as
    1.10 + * published by the Free Software Foundation.  Oracle designates this
    1.11 + * particular file as subject to the "Classpath" exception as provided
    1.12 + * by Oracle in the LICENSE file that accompanied this code.
    1.13 + *
    1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    1.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    1.17 + * version 2 for more details (a copy is included in the LICENSE file that
    1.18 + * accompanied this code).
    1.19 + *
    1.20 + * You should have received a copy of the GNU General Public License version
    1.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    1.23 + *
    1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    1.25 + * or visit www.oracle.com if you need additional information or have any
    1.26 + * questions.
    1.27 + */
    1.28 +
    1.29 +package java.io;
    1.30 +
    1.31 +import java.lang.reflect.Array;
    1.32 +import java.lang.reflect.Modifier;
    1.33 +import java.lang.reflect.Proxy;
    1.34 +import java.util.Arrays;
    1.35 +import java.util.HashMap;
    1.36 +import org.apidesign.bck2brwsr.emul.lang.System;
    1.37 +
    1.38 +/**
    1.39 + * An ObjectInputStream deserializes primitive data and objects previously
    1.40 + * written using an ObjectOutputStream.
    1.41 + *
    1.42 + * <p>ObjectOutputStream and ObjectInputStream can provide an application with
    1.43 + * persistent storage for graphs of objects when used with a FileOutputStream
    1.44 + * and FileInputStream respectively.  ObjectInputStream is used to recover
    1.45 + * those objects previously serialized. Other uses include passing objects
    1.46 + * between hosts using a socket stream or for marshaling and unmarshaling
    1.47 + * arguments and parameters in a remote communication system.
    1.48 + *
    1.49 + * <p>ObjectInputStream ensures that the types of all objects in the graph
    1.50 + * created from the stream match the classes present in the Java Virtual
    1.51 + * Machine.  Classes are loaded as required using the standard mechanisms.
    1.52 + *
    1.53 + * <p>Only objects that support the java.io.Serializable or
    1.54 + * java.io.Externalizable interface can be read from streams.
    1.55 + *
    1.56 + * <p>The method <code>readObject</code> is used to read an object from the
    1.57 + * stream.  Java's safe casting should be used to get the desired type.  In
    1.58 + * Java, strings and arrays are objects and are treated as objects during
    1.59 + * serialization. When read they need to be cast to the expected type.
    1.60 + *
    1.61 + * <p>Primitive data types can be read from the stream using the appropriate
    1.62 + * method on DataInput.
    1.63 + *
    1.64 + * <p>The default deserialization mechanism for objects restores the contents
    1.65 + * of each field to the value and type it had when it was written.  Fields
    1.66 + * declared as transient or static are ignored by the deserialization process.
    1.67 + * References to other objects cause those objects to be read from the stream
    1.68 + * as necessary.  Graphs of objects are restored correctly using a reference
    1.69 + * sharing mechanism.  New objects are always allocated when deserializing,
    1.70 + * which prevents existing objects from being overwritten.
    1.71 + *
    1.72 + * <p>Reading an object is analogous to running the constructors of a new
    1.73 + * object.  Memory is allocated for the object and initialized to zero (NULL).
    1.74 + * No-arg constructors are invoked for the non-serializable classes and then
    1.75 + * the fields of the serializable classes are restored from the stream starting
    1.76 + * with the serializable class closest to java.lang.object and finishing with
    1.77 + * the object's most specific class.
    1.78 + *
    1.79 + * <p>For example to read from a stream as written by the example in
    1.80 + * ObjectOutputStream:
    1.81 + * <br>
    1.82 + * <pre>
    1.83 + *      FileInputStream fis = new FileInputStream("t.tmp");
    1.84 + *      ObjectInputStream ois = new ObjectInputStream(fis);
    1.85 + *
    1.86 + *      int i = ois.readInt();
    1.87 + *      String today = (String) ois.readObject();
    1.88 + *      Date date = (Date) ois.readObject();
    1.89 + *
    1.90 + *      ois.close();
    1.91 + * </pre>
    1.92 + *
    1.93 + * <p>Classes control how they are serialized by implementing either the
    1.94 + * java.io.Serializable or java.io.Externalizable interfaces.
    1.95 + *
    1.96 + * <p>Implementing the Serializable interface allows object serialization to
    1.97 + * save and restore the entire state of the object and it allows classes to
    1.98 + * evolve between the time the stream is written and the time it is read.  It
    1.99 + * automatically traverses references between objects, saving and restoring
   1.100 + * entire graphs.
   1.101 + *
   1.102 + * <p>Serializable classes that require special handling during the
   1.103 + * serialization and deserialization process should implement the following
   1.104 + * methods:<p>
   1.105 + *
   1.106 + * <pre>
   1.107 + * private void writeObject(java.io.ObjectOutputStream stream)
   1.108 + *     throws IOException;
   1.109 + * private void readObject(java.io.ObjectInputStream stream)
   1.110 + *     throws IOException, ClassNotFoundException;
   1.111 + * private void readObjectNoData()
   1.112 + *     throws ObjectStreamException;
   1.113 + * </pre>
   1.114 + *
   1.115 + * <p>The readObject method is responsible for reading and restoring the state
   1.116 + * of the object for its particular class using data written to the stream by
   1.117 + * the corresponding writeObject method.  The method does not need to concern
   1.118 + * itself with the state belonging to its superclasses or subclasses.  State is
   1.119 + * restored by reading data from the ObjectInputStream for the individual
   1.120 + * fields and making assignments to the appropriate fields of the object.
   1.121 + * Reading primitive data types is supported by DataInput.
   1.122 + *
   1.123 + * <p>Any attempt to read object data which exceeds the boundaries of the
   1.124 + * custom data written by the corresponding writeObject method will cause an
   1.125 + * OptionalDataException to be thrown with an eof field value of true.
   1.126 + * Non-object reads which exceed the end of the allotted data will reflect the
   1.127 + * end of data in the same way that they would indicate the end of the stream:
   1.128 + * bytewise reads will return -1 as the byte read or number of bytes read, and
   1.129 + * primitive reads will throw EOFExceptions.  If there is no corresponding
   1.130 + * writeObject method, then the end of default serialized data marks the end of
   1.131 + * the allotted data.
   1.132 + *
   1.133 + * <p>Primitive and object read calls issued from within a readExternal method
   1.134 + * behave in the same manner--if the stream is already positioned at the end of
   1.135 + * data written by the corresponding writeExternal method, object reads will
   1.136 + * throw OptionalDataExceptions with eof set to true, bytewise reads will
   1.137 + * return -1, and primitive reads will throw EOFExceptions.  Note that this
   1.138 + * behavior does not hold for streams written with the old
   1.139 + * <code>ObjectStreamConstants.PROTOCOL_VERSION_1</code> protocol, in which the
   1.140 + * end of data written by writeExternal methods is not demarcated, and hence
   1.141 + * cannot be detected.
   1.142 + *
   1.143 + * <p>The readObjectNoData method is responsible for initializing the state of
   1.144 + * the object for its particular class in the event that the serialization
   1.145 + * stream does not list the given class as a superclass of the object being
   1.146 + * deserialized.  This may occur in cases where the receiving party uses a
   1.147 + * different version of the deserialized instance's class than the sending
   1.148 + * party, and the receiver's version extends classes that are not extended by
   1.149 + * the sender's version.  This may also occur if the serialization stream has
   1.150 + * been tampered; hence, readObjectNoData is useful for initializing
   1.151 + * deserialized objects properly despite a "hostile" or incomplete source
   1.152 + * stream.
   1.153 + *
   1.154 + * <p>Serialization does not read or assign values to the fields of any object
   1.155 + * that does not implement the java.io.Serializable interface.  Subclasses of
   1.156 + * Objects that are not serializable can be serializable. In this case the
   1.157 + * non-serializable class must have a no-arg constructor to allow its fields to
   1.158 + * be initialized.  In this case it is the responsibility of the subclass to
   1.159 + * save and restore the state of the non-serializable class. It is frequently
   1.160 + * the case that the fields of that class are accessible (public, package, or
   1.161 + * protected) or that there are get and set methods that can be used to restore
   1.162 + * the state.
   1.163 + *
   1.164 + * <p>Any exception that occurs while deserializing an object will be caught by
   1.165 + * the ObjectInputStream and abort the reading process.
   1.166 + *
   1.167 + * <p>Implementing the Externalizable interface allows the object to assume
   1.168 + * complete control over the contents and format of the object's serialized
   1.169 + * form.  The methods of the Externalizable interface, writeExternal and
   1.170 + * readExternal, are called to save and restore the objects state.  When
   1.171 + * implemented by a class they can write and read their own state using all of
   1.172 + * the methods of ObjectOutput and ObjectInput.  It is the responsibility of
   1.173 + * the objects to handle any versioning that occurs.
   1.174 + *
   1.175 + * <p>Enum constants are deserialized differently than ordinary serializable or
   1.176 + * externalizable objects.  The serialized form of an enum constant consists
   1.177 + * solely of its name; field values of the constant are not transmitted.  To
   1.178 + * deserialize an enum constant, ObjectInputStream reads the constant name from
   1.179 + * the stream; the deserialized constant is then obtained by calling the static
   1.180 + * method <code>Enum.valueOf(Class, String)</code> with the enum constant's
   1.181 + * base type and the received constant name as arguments.  Like other
   1.182 + * serializable or externalizable objects, enum constants can function as the
   1.183 + * targets of back references appearing subsequently in the serialization
   1.184 + * stream.  The process by which enum constants are deserialized cannot be
   1.185 + * customized: any class-specific readObject, readObjectNoData, and readResolve
   1.186 + * methods defined by enum types are ignored during deserialization.
   1.187 + * Similarly, any serialPersistentFields or serialVersionUID field declarations
   1.188 + * are also ignored--all enum types have a fixed serialVersionUID of 0L.
   1.189 + *
   1.190 + * @author      Mike Warres
   1.191 + * @author      Roger Riggs
   1.192 + * @see java.io.DataInput
   1.193 + * @see java.io.ObjectOutputStream
   1.194 + * @see java.io.Serializable
   1.195 + * @see <a href="../../../platform/serialization/spec/input.html"> Object Serialization Specification, Section 3, Object Input Classes</a>
   1.196 + * @since   JDK1.1
   1.197 + */
   1.198 +public class ObjectInputStream
   1.199 +    extends InputStream implements ObjectInput, ObjectStreamConstants
   1.200 +{
   1.201 +    /** handle value representing null */
   1.202 +    private static final int NULL_HANDLE = -1;
   1.203 +
   1.204 +    /** marker for unshared objects in internal handle table */
   1.205 +    private static final Object unsharedMarker = new Object();
   1.206 +
   1.207 +    /** table mapping primitive type names to corresponding class objects */
   1.208 +    private static final HashMap<String, Class<?>> primClasses
   1.209 +        = new HashMap<>(8, 1.0F);
   1.210 +    static {
   1.211 +        primClasses.put("boolean", boolean.class);
   1.212 +        primClasses.put("byte", byte.class);
   1.213 +        primClasses.put("char", char.class);
   1.214 +        primClasses.put("short", short.class);
   1.215 +        primClasses.put("int", int.class);
   1.216 +        primClasses.put("long", long.class);
   1.217 +        primClasses.put("float", float.class);
   1.218 +        primClasses.put("double", double.class);
   1.219 +        primClasses.put("void", void.class);
   1.220 +    }
   1.221 +
   1.222 +    /** filter stream for handling block data conversion */
   1.223 +    private final BlockDataInputStream bin;
   1.224 +    /** validation callback list */
   1.225 +    private final ValidationList vlist;
   1.226 +    /** recursion depth */
   1.227 +    private int depth;
   1.228 +    /** whether stream is closed */
   1.229 +    private boolean closed;
   1.230 +
   1.231 +    /** wire handle -> obj/exception map */
   1.232 +    private final HandleTable handles;
   1.233 +    /** scratch field for passing handle values up/down call stack */
   1.234 +    private int passHandle = NULL_HANDLE;
   1.235 +    /** flag set when at end of field value block with no TC_ENDBLOCKDATA */
   1.236 +    private boolean defaultDataEnd = false;
   1.237 +
   1.238 +    /** buffer for reading primitive field values */
   1.239 +    private byte[] primVals;
   1.240 +
   1.241 +    /** if true, invoke readObjectOverride() instead of readObject() */
   1.242 +    private final boolean enableOverride;
   1.243 +    /** if true, invoke resolveObject() */
   1.244 +    private boolean enableResolve;
   1.245 +
   1.246 +    /**
   1.247 +     * Context during upcalls to class-defined readObject methods; holds
   1.248 +     * object currently being deserialized and descriptor for current class.
   1.249 +     * Null when not during readObject upcall.
   1.250 +     */
   1.251 +    private Object curContext;
   1.252 +
   1.253 +    /**
   1.254 +     * Creates an ObjectInputStream that reads from the specified InputStream.
   1.255 +     * A serialization stream header is read from the stream and verified.
   1.256 +     * This constructor will block until the corresponding ObjectOutputStream
   1.257 +     * has written and flushed the header.
   1.258 +     *
   1.259 +     * <p>If a security manager is installed, this constructor will check for
   1.260 +     * the "enableSubclassImplementation" SerializablePermission when invoked
   1.261 +     * directly or indirectly by the constructor of a subclass which overrides
   1.262 +     * the ObjectInputStream.readFields or ObjectInputStream.readUnshared
   1.263 +     * methods.
   1.264 +     *
   1.265 +     * @param   in input stream to read from
   1.266 +     * @throws  StreamCorruptedException if the stream header is incorrect
   1.267 +     * @throws  IOException if an I/O error occurs while reading stream header
   1.268 +     * @throws  SecurityException if untrusted subclass illegally overrides
   1.269 +     *          security-sensitive methods
   1.270 +     * @throws  NullPointerException if <code>in</code> is <code>null</code>
   1.271 +     * @see     ObjectInputStream#ObjectInputStream()
   1.272 +     * @see     ObjectInputStream#readFields()
   1.273 +     * @see     ObjectOutputStream#ObjectOutputStream(OutputStream)
   1.274 +     */
   1.275 +    public ObjectInputStream(InputStream in) throws IOException {
   1.276 +        verifySubclass();
   1.277 +        bin = new BlockDataInputStream(in);
   1.278 +        handles = new HandleTable(10);
   1.279 +        vlist = new ValidationList();
   1.280 +        enableOverride = false;
   1.281 +        readStreamHeader();
   1.282 +        bin.setBlockDataMode(true);
   1.283 +    }
   1.284 +
   1.285 +    /**
   1.286 +     * Provide a way for subclasses that are completely reimplementing
   1.287 +     * ObjectInputStream to not have to allocate private data just used by this
   1.288 +     * implementation of ObjectInputStream.
   1.289 +     *
   1.290 +     * <p>If there is a security manager installed, this method first calls the
   1.291 +     * security manager's <code>checkPermission</code> method with the
   1.292 +     * <code>SerializablePermission("enableSubclassImplementation")</code>
   1.293 +     * permission to ensure it's ok to enable subclassing.
   1.294 +     *
   1.295 +     * @throws  SecurityException if a security manager exists and its
   1.296 +     *          <code>checkPermission</code> method denies enabling
   1.297 +     *          subclassing.
   1.298 +     * @see SecurityManager#checkPermission
   1.299 +     * @see java.io.SerializablePermission
   1.300 +     */
   1.301 +    protected ObjectInputStream() throws IOException, SecurityException {
   1.302 +        throw new SecurityException();
   1.303 +    }
   1.304 +
   1.305 +    /**
   1.306 +     * Read an object from the ObjectInputStream.  The class of the object, the
   1.307 +     * signature of the class, and the values of the non-transient and
   1.308 +     * non-static fields of the class and all of its supertypes are read.
   1.309 +     * Default deserializing for a class can be overriden using the writeObject
   1.310 +     * and readObject methods.  Objects referenced by this object are read
   1.311 +     * transitively so that a complete equivalent graph of objects is
   1.312 +     * reconstructed by readObject.
   1.313 +     *
   1.314 +     * <p>The root object is completely restored when all of its fields and the
   1.315 +     * objects it references are completely restored.  At this point the object
   1.316 +     * validation callbacks are executed in order based on their registered
   1.317 +     * priorities. The callbacks are registered by objects (in the readObject
   1.318 +     * special methods) as they are individually restored.
   1.319 +     *
   1.320 +     * <p>Exceptions are thrown for problems with the InputStream and for
   1.321 +     * classes that should not be deserialized.  All exceptions are fatal to
   1.322 +     * the InputStream and leave it in an indeterminate state; it is up to the
   1.323 +     * caller to ignore or recover the stream state.
   1.324 +     *
   1.325 +     * @throws  ClassNotFoundException Class of a serialized object cannot be
   1.326 +     *          found.
   1.327 +     * @throws  InvalidClassException Something is wrong with a class used by
   1.328 +     *          serialization.
   1.329 +     * @throws  StreamCorruptedException Control information in the
   1.330 +     *          stream is inconsistent.
   1.331 +     * @throws  OptionalDataException Primitive data was found in the
   1.332 +     *          stream instead of objects.
   1.333 +     * @throws  IOException Any of the usual Input/Output related exceptions.
   1.334 +     */
   1.335 +    public final Object readObject()
   1.336 +        throws IOException, ClassNotFoundException
   1.337 +    {
   1.338 +        throw new IOException();
   1.339 +    }
   1.340 +
   1.341 +    /**
   1.342 +     * This method is called by trusted subclasses of ObjectOutputStream that
   1.343 +     * constructed ObjectOutputStream using the protected no-arg constructor.
   1.344 +     * The subclass is expected to provide an override method with the modifier
   1.345 +     * "final".
   1.346 +     *
   1.347 +     * @return  the Object read from the stream.
   1.348 +     * @throws  ClassNotFoundException Class definition of a serialized object
   1.349 +     *          cannot be found.
   1.350 +     * @throws  OptionalDataException Primitive data was found in the stream
   1.351 +     *          instead of objects.
   1.352 +     * @throws  IOException if I/O errors occurred while reading from the
   1.353 +     *          underlying stream
   1.354 +     * @see #ObjectInputStream()
   1.355 +     * @see #readObject()
   1.356 +     * @since 1.2
   1.357 +     */
   1.358 +    protected Object readObjectOverride()
   1.359 +        throws IOException, ClassNotFoundException
   1.360 +    {
   1.361 +        return null;
   1.362 +    }
   1.363 +
   1.364 +    /**
   1.365 +     * Reads an "unshared" object from the ObjectInputStream.  This method is
   1.366 +     * identical to readObject, except that it prevents subsequent calls to
   1.367 +     * readObject and readUnshared from returning additional references to the
   1.368 +     * deserialized instance obtained via this call.  Specifically:
   1.369 +     * <ul>
   1.370 +     *   <li>If readUnshared is called to deserialize a back-reference (the
   1.371 +     *       stream representation of an object which has been written
   1.372 +     *       previously to the stream), an ObjectStreamException will be
   1.373 +     *       thrown.
   1.374 +     *
   1.375 +     *   <li>If readUnshared returns successfully, then any subsequent attempts
   1.376 +     *       to deserialize back-references to the stream handle deserialized
   1.377 +     *       by readUnshared will cause an ObjectStreamException to be thrown.
   1.378 +     * </ul>
   1.379 +     * Deserializing an object via readUnshared invalidates the stream handle
   1.380 +     * associated with the returned object.  Note that this in itself does not
   1.381 +     * always guarantee that the reference returned by readUnshared is unique;
   1.382 +     * the deserialized object may define a readResolve method which returns an
   1.383 +     * object visible to other parties, or readUnshared may return a Class
   1.384 +     * object or enum constant obtainable elsewhere in the stream or through
   1.385 +     * external means. If the deserialized object defines a readResolve method
   1.386 +     * and the invocation of that method returns an array, then readUnshared
   1.387 +     * returns a shallow clone of that array; this guarantees that the returned
   1.388 +     * array object is unique and cannot be obtained a second time from an
   1.389 +     * invocation of readObject or readUnshared on the ObjectInputStream,
   1.390 +     * even if the underlying data stream has been manipulated.
   1.391 +     *
   1.392 +     * <p>ObjectInputStream subclasses which override this method can only be
   1.393 +     * constructed in security contexts possessing the
   1.394 +     * "enableSubclassImplementation" SerializablePermission; any attempt to
   1.395 +     * instantiate such a subclass without this permission will cause a
   1.396 +     * SecurityException to be thrown.
   1.397 +     *
   1.398 +     * @return  reference to deserialized object
   1.399 +     * @throws  ClassNotFoundException if class of an object to deserialize
   1.400 +     *          cannot be found
   1.401 +     * @throws  StreamCorruptedException if control information in the stream
   1.402 +     *          is inconsistent
   1.403 +     * @throws  ObjectStreamException if object to deserialize has already
   1.404 +     *          appeared in stream
   1.405 +     * @throws  OptionalDataException if primitive data is next in stream
   1.406 +     * @throws  IOException if an I/O error occurs during deserialization
   1.407 +     * @since   1.4
   1.408 +     */
   1.409 +    public Object readUnshared() throws IOException, ClassNotFoundException {
   1.410 +        // if nested read, passHandle contains handle of enclosing object
   1.411 +        int outerHandle = passHandle;
   1.412 +        try {
   1.413 +            Object obj = readObject0(true);
   1.414 +            handles.markDependency(outerHandle, passHandle);
   1.415 +            ClassNotFoundException ex = handles.lookupException(passHandle);
   1.416 +            if (ex != null) {
   1.417 +                throw ex;
   1.418 +            }
   1.419 +            if (depth == 0) {
   1.420 +                vlist.doCallbacks();
   1.421 +            }
   1.422 +            return obj;
   1.423 +        } finally {
   1.424 +            passHandle = outerHandle;
   1.425 +            if (closed && depth == 0) {
   1.426 +                clear();
   1.427 +            }
   1.428 +        }
   1.429 +    }
   1.430 +
   1.431 +    /**
   1.432 +     * Read the non-static and non-transient fields of the current class from
   1.433 +     * this stream.  This may only be called from the readObject method of the
   1.434 +     * class being deserialized. It will throw the NotActiveException if it is
   1.435 +     * called otherwise.
   1.436 +     *
   1.437 +     * @throws  ClassNotFoundException if the class of a serialized object
   1.438 +     *          could not be found.
   1.439 +     * @throws  IOException if an I/O error occurs.
   1.440 +     * @throws  NotActiveException if the stream is not currently reading
   1.441 +     *          objects.
   1.442 +     */
   1.443 +    public void defaultReadObject()
   1.444 +        throws IOException, ClassNotFoundException
   1.445 +    {
   1.446 +        if (curContext == null) {
   1.447 +            throw new NotActiveException("not in call to readObject");
   1.448 +        }
   1.449 +        Object curObj = null; // curContext.getObj();
   1.450 +        ObjectStreamClass curDesc = null; // curContext.getDesc();
   1.451 +        bin.setBlockDataMode(false);
   1.452 +        defaultReadFields(curObj, curDesc);
   1.453 +        bin.setBlockDataMode(true);
   1.454 +        if (!curDesc.hasWriteObjectData()) {
   1.455 +            /*
   1.456 +             * Fix for 4360508: since stream does not contain terminating
   1.457 +             * TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere
   1.458 +             * knows to simulate end-of-custom-data behavior.
   1.459 +             */
   1.460 +            defaultDataEnd = true;
   1.461 +        }
   1.462 +        ClassNotFoundException ex = handles.lookupException(passHandle);
   1.463 +        if (ex != null) {
   1.464 +            throw ex;
   1.465 +        }
   1.466 +    }
   1.467 +
   1.468 +    /**
   1.469 +     * Reads the persistent fields from the stream and makes them available by
   1.470 +     * name.
   1.471 +     *
   1.472 +     * @return  the <code>GetField</code> object representing the persistent
   1.473 +     *          fields of the object being deserialized
   1.474 +     * @throws  ClassNotFoundException if the class of a serialized object
   1.475 +     *          could not be found.
   1.476 +     * @throws  IOException if an I/O error occurs.
   1.477 +     * @throws  NotActiveException if the stream is not currently reading
   1.478 +     *          objects.
   1.479 +     * @since 1.2
   1.480 +     */
   1.481 +    public ObjectInputStream.GetField readFields()
   1.482 +        throws IOException, ClassNotFoundException
   1.483 +    {
   1.484 +        if (curContext == null) {
   1.485 +            throw new NotActiveException("not in call to readObject");
   1.486 +        }
   1.487 +        Object curObj = null; // curContext.getObj();
   1.488 +        ObjectStreamClass curDesc = null; // curContext.getDesc();
   1.489 +        bin.setBlockDataMode(false);
   1.490 +        GetFieldImpl getField = new GetFieldImpl(curDesc);
   1.491 +        getField.readFields();
   1.492 +        bin.setBlockDataMode(true);
   1.493 +        if (!curDesc.hasWriteObjectData()) {
   1.494 +            /*
   1.495 +             * Fix for 4360508: since stream does not contain terminating
   1.496 +             * TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere
   1.497 +             * knows to simulate end-of-custom-data behavior.
   1.498 +             */
   1.499 +            defaultDataEnd = true;
   1.500 +        }
   1.501 +
   1.502 +        return getField;
   1.503 +    }
   1.504 +
   1.505 +    /**
   1.506 +     * Register an object to be validated before the graph is returned.  While
   1.507 +     * similar to resolveObject these validations are called after the entire
   1.508 +     * graph has been reconstituted.  Typically, a readObject method will
   1.509 +     * register the object with the stream so that when all of the objects are
   1.510 +     * restored a final set of validations can be performed.
   1.511 +     *
   1.512 +     * @param   obj the object to receive the validation callback.
   1.513 +     * @param   prio controls the order of callbacks;zero is a good default.
   1.514 +     *          Use higher numbers to be called back earlier, lower numbers for
   1.515 +     *          later callbacks. Within a priority, callbacks are processed in
   1.516 +     *          no particular order.
   1.517 +     * @throws  NotActiveException The stream is not currently reading objects
   1.518 +     *          so it is invalid to register a callback.
   1.519 +     * @throws  InvalidObjectException The validation object is null.
   1.520 +     */
   1.521 +    public void registerValidation(ObjectInputValidation obj, int prio)
   1.522 +        throws NotActiveException, InvalidObjectException
   1.523 +    {
   1.524 +        if (depth == 0) {
   1.525 +            throw new NotActiveException("stream inactive");
   1.526 +        }
   1.527 +        vlist.register(obj, prio);
   1.528 +    }
   1.529 +
   1.530 +    /**
   1.531 +     * Load the local class equivalent of the specified stream class
   1.532 +     * description.  Subclasses may implement this method to allow classes to
   1.533 +     * be fetched from an alternate source.
   1.534 +     *
   1.535 +     * <p>The corresponding method in <code>ObjectOutputStream</code> is
   1.536 +     * <code>annotateClass</code>.  This method will be invoked only once for
   1.537 +     * each unique class in the stream.  This method can be implemented by
   1.538 +     * subclasses to use an alternate loading mechanism but must return a
   1.539 +     * <code>Class</code> object. Once returned, if the class is not an array
   1.540 +     * class, its serialVersionUID is compared to the serialVersionUID of the
   1.541 +     * serialized class, and if there is a mismatch, the deserialization fails
   1.542 +     * and an {@link InvalidClassException} is thrown.
   1.543 +     *
   1.544 +     * <p>The default implementation of this method in
   1.545 +     * <code>ObjectInputStream</code> returns the result of calling
   1.546 +     * <pre>
   1.547 +     *     Class.forName(desc.getName(), false, loader)
   1.548 +     * </pre>
   1.549 +     * where <code>loader</code> is determined as follows: if there is a
   1.550 +     * method on the current thread's stack whose declaring class was
   1.551 +     * defined by a user-defined class loader (and was not a generated to
   1.552 +     * implement reflective invocations), then <code>loader</code> is class
   1.553 +     * loader corresponding to the closest such method to the currently
   1.554 +     * executing frame; otherwise, <code>loader</code> is
   1.555 +     * <code>null</code>. If this call results in a
   1.556 +     * <code>ClassNotFoundException</code> and the name of the passed
   1.557 +     * <code>ObjectStreamClass</code> instance is the Java language keyword
   1.558 +     * for a primitive type or void, then the <code>Class</code> object
   1.559 +     * representing that primitive type or void will be returned
   1.560 +     * (e.g., an <code>ObjectStreamClass</code> with the name
   1.561 +     * <code>"int"</code> will be resolved to <code>Integer.TYPE</code>).
   1.562 +     * Otherwise, the <code>ClassNotFoundException</code> will be thrown to
   1.563 +     * the caller of this method.
   1.564 +     *
   1.565 +     * @param   desc an instance of class <code>ObjectStreamClass</code>
   1.566 +     * @return  a <code>Class</code> object corresponding to <code>desc</code>
   1.567 +     * @throws  IOException any of the usual Input/Output exceptions.
   1.568 +     * @throws  ClassNotFoundException if class of a serialized object cannot
   1.569 +     *          be found.
   1.570 +     */
   1.571 +    protected Class<?> resolveClass(ObjectStreamClass desc)
   1.572 +        throws IOException, ClassNotFoundException
   1.573 +    {
   1.574 +        String name = desc.getName();
   1.575 +        try {
   1.576 +            return Class.forName(name, false, latestUserDefinedLoader());
   1.577 +        } catch (ClassNotFoundException ex) {
   1.578 +            Class<?> cl = primClasses.get(name);
   1.579 +            if (cl != null) {
   1.580 +                return cl;
   1.581 +            } else {
   1.582 +                throw ex;
   1.583 +            }
   1.584 +        }
   1.585 +    }
   1.586 +
   1.587 +    /**
   1.588 +     * Returns a proxy class that implements the interfaces named in a proxy
   1.589 +     * class descriptor; subclasses may implement this method to read custom
   1.590 +     * data from the stream along with the descriptors for dynamic proxy
   1.591 +     * classes, allowing them to use an alternate loading mechanism for the
   1.592 +     * interfaces and the proxy class.
   1.593 +     *
   1.594 +     * <p>This method is called exactly once for each unique proxy class
   1.595 +     * descriptor in the stream.
   1.596 +     *
   1.597 +     * <p>The corresponding method in <code>ObjectOutputStream</code> is
   1.598 +     * <code>annotateProxyClass</code>.  For a given subclass of
   1.599 +     * <code>ObjectInputStream</code> that overrides this method, the
   1.600 +     * <code>annotateProxyClass</code> method in the corresponding subclass of
   1.601 +     * <code>ObjectOutputStream</code> must write any data or objects read by
   1.602 +     * this method.
   1.603 +     *
   1.604 +     * <p>The default implementation of this method in
   1.605 +     * <code>ObjectInputStream</code> returns the result of calling
   1.606 +     * <code>Proxy.getProxyClass</code> with the list of <code>Class</code>
   1.607 +     * objects for the interfaces that are named in the <code>interfaces</code>
   1.608 +     * parameter.  The <code>Class</code> object for each interface name
   1.609 +     * <code>i</code> is the value returned by calling
   1.610 +     * <pre>
   1.611 +     *     Class.forName(i, false, loader)
   1.612 +     * </pre>
   1.613 +     * where <code>loader</code> is that of the first non-<code>null</code>
   1.614 +     * class loader up the execution stack, or <code>null</code> if no
   1.615 +     * non-<code>null</code> class loaders are on the stack (the same class
   1.616 +     * loader choice used by the <code>resolveClass</code> method).  Unless any
   1.617 +     * of the resolved interfaces are non-public, this same value of
   1.618 +     * <code>loader</code> is also the class loader passed to
   1.619 +     * <code>Proxy.getProxyClass</code>; if non-public interfaces are present,
   1.620 +     * their class loader is passed instead (if more than one non-public
   1.621 +     * interface class loader is encountered, an
   1.622 +     * <code>IllegalAccessError</code> is thrown).
   1.623 +     * If <code>Proxy.getProxyClass</code> throws an
   1.624 +     * <code>IllegalArgumentException</code>, <code>resolveProxyClass</code>
   1.625 +     * will throw a <code>ClassNotFoundException</code> containing the
   1.626 +     * <code>IllegalArgumentException</code>.
   1.627 +     *
   1.628 +     * @param interfaces the list of interface names that were
   1.629 +     *                deserialized in the proxy class descriptor
   1.630 +     * @return  a proxy class for the specified interfaces
   1.631 +     * @throws        IOException any exception thrown by the underlying
   1.632 +     *                <code>InputStream</code>
   1.633 +     * @throws        ClassNotFoundException if the proxy class or any of the
   1.634 +     *                named interfaces could not be found
   1.635 +     * @see ObjectOutputStream#annotateProxyClass(Class)
   1.636 +     * @since 1.3
   1.637 +     */
   1.638 +    protected Class<?> resolveProxyClass(String[] interfaces)
   1.639 +        throws IOException, ClassNotFoundException
   1.640 +    {
   1.641 +        ClassLoader latestLoader = latestUserDefinedLoader();
   1.642 +        ClassLoader nonPublicLoader = null;
   1.643 +        boolean hasNonPublicInterface = false;
   1.644 +
   1.645 +        // define proxy in class loader of non-public interface(s), if any
   1.646 +        Class[] classObjs = new Class[interfaces.length];
   1.647 +        for (int i = 0; i < interfaces.length; i++) {
   1.648 +            Class cl = Class.forName(interfaces[i], false, latestLoader);
   1.649 +            if ((cl.getModifiers() & Modifier.PUBLIC) == 0) {
   1.650 +                if (hasNonPublicInterface) {
   1.651 +                    if (nonPublicLoader != cl.getClassLoader()) {
   1.652 +                        throw new IllegalAccessError(
   1.653 +                            "conflicting non-public interface class loaders");
   1.654 +                    }
   1.655 +                } else {
   1.656 +                    nonPublicLoader = cl.getClassLoader();
   1.657 +                    hasNonPublicInterface = true;
   1.658 +                }
   1.659 +            }
   1.660 +            classObjs[i] = cl;
   1.661 +        }
   1.662 +        try {
   1.663 +            return Proxy.getProxyClass(
   1.664 +                hasNonPublicInterface ? nonPublicLoader : latestLoader,
   1.665 +                classObjs);
   1.666 +        } catch (IllegalArgumentException e) {
   1.667 +            throw new ClassNotFoundException(null, e);
   1.668 +        }
   1.669 +    }
   1.670 +
   1.671 +    /**
   1.672 +     * This method will allow trusted subclasses of ObjectInputStream to
   1.673 +     * substitute one object for another during deserialization. Replacing
   1.674 +     * objects is disabled until enableResolveObject is called. The
   1.675 +     * enableResolveObject method checks that the stream requesting to resolve
   1.676 +     * object can be trusted. Every reference to serializable objects is passed
   1.677 +     * to resolveObject.  To insure that the private state of objects is not
   1.678 +     * unintentionally exposed only trusted streams may use resolveObject.
   1.679 +     *
   1.680 +     * <p>This method is called after an object has been read but before it is
   1.681 +     * returned from readObject.  The default resolveObject method just returns
   1.682 +     * the same object.
   1.683 +     *
   1.684 +     * <p>When a subclass is replacing objects it must insure that the
   1.685 +     * substituted object is compatible with every field where the reference
   1.686 +     * will be stored.  Objects whose type is not a subclass of the type of the
   1.687 +     * field or array element abort the serialization by raising an exception
   1.688 +     * and the object is not be stored.
   1.689 +     *
   1.690 +     * <p>This method is called only once when each object is first
   1.691 +     * encountered.  All subsequent references to the object will be redirected
   1.692 +     * to the new object.
   1.693 +     *
   1.694 +     * @param   obj object to be substituted
   1.695 +     * @return  the substituted object
   1.696 +     * @throws  IOException Any of the usual Input/Output exceptions.
   1.697 +     */
   1.698 +    protected Object resolveObject(Object obj) throws IOException {
   1.699 +        return obj;
   1.700 +    }
   1.701 +
   1.702 +    /**
   1.703 +     * Enable the stream to allow objects read from the stream to be replaced.
   1.704 +     * When enabled, the resolveObject method is called for every object being
   1.705 +     * deserialized.
   1.706 +     *
   1.707 +     * <p>If <i>enable</i> is true, and there is a security manager installed,
   1.708 +     * this method first calls the security manager's
   1.709 +     * <code>checkPermission</code> method with the
   1.710 +     * <code>SerializablePermission("enableSubstitution")</code> permission to
   1.711 +     * ensure it's ok to enable the stream to allow objects read from the
   1.712 +     * stream to be replaced.
   1.713 +     *
   1.714 +     * @param   enable true for enabling use of <code>resolveObject</code> for
   1.715 +     *          every object being deserialized
   1.716 +     * @return  the previous setting before this method was invoked
   1.717 +     * @throws  SecurityException if a security manager exists and its
   1.718 +     *          <code>checkPermission</code> method denies enabling the stream
   1.719 +     *          to allow objects read from the stream to be replaced.
   1.720 +     * @see SecurityManager#checkPermission
   1.721 +     * @see java.io.SerializablePermission
   1.722 +     */
   1.723 +    protected boolean enableResolveObject(boolean enable)
   1.724 +        throws SecurityException
   1.725 +    {
   1.726 +        throw new SecurityException();
   1.727 +    }
   1.728 +
   1.729 +    /**
   1.730 +     * The readStreamHeader method is provided to allow subclasses to read and
   1.731 +     * verify their own stream headers. It reads and verifies the magic number
   1.732 +     * and version number.
   1.733 +     *
   1.734 +     * @throws  IOException if there are I/O errors while reading from the
   1.735 +     *          underlying <code>InputStream</code>
   1.736 +     * @throws  StreamCorruptedException if control information in the stream
   1.737 +     *          is inconsistent
   1.738 +     */
   1.739 +    protected void readStreamHeader()
   1.740 +        throws IOException, StreamCorruptedException
   1.741 +    {
   1.742 +        short s0 = bin.readShort();
   1.743 +        short s1 = bin.readShort();
   1.744 +        if (s0 != STREAM_MAGIC || s1 != STREAM_VERSION) {
   1.745 +            throw new StreamCorruptedException(
   1.746 +                String.format("invalid stream header: %04X%04X", s0, s1));
   1.747 +        }
   1.748 +    }
   1.749 +
   1.750 +    /**
   1.751 +     * Read a class descriptor from the serialization stream.  This method is
   1.752 +     * called when the ObjectInputStream expects a class descriptor as the next
   1.753 +     * item in the serialization stream.  Subclasses of ObjectInputStream may
   1.754 +     * override this method to read in class descriptors that have been written
   1.755 +     * in non-standard formats (by subclasses of ObjectOutputStream which have
   1.756 +     * overridden the <code>writeClassDescriptor</code> method).  By default,
   1.757 +     * this method reads class descriptors according to the format defined in
   1.758 +     * the Object Serialization specification.
   1.759 +     *
   1.760 +     * @return  the class descriptor read
   1.761 +     * @throws  IOException If an I/O error has occurred.
   1.762 +     * @throws  ClassNotFoundException If the Class of a serialized object used
   1.763 +     *          in the class descriptor representation cannot be found
   1.764 +     * @see java.io.ObjectOutputStream#writeClassDescriptor(java.io.ObjectStreamClass)
   1.765 +     * @since 1.3
   1.766 +     */
   1.767 +    protected ObjectStreamClass readClassDescriptor()
   1.768 +        throws IOException, ClassNotFoundException
   1.769 +    {
   1.770 +        ObjectStreamClass desc = new ObjectStreamClass();
   1.771 +        desc.readNonProxy(this);
   1.772 +        return desc;
   1.773 +    }
   1.774 +
   1.775 +    /**
   1.776 +     * Reads a byte of data. This method will block if no input is available.
   1.777 +     *
   1.778 +     * @return  the byte read, or -1 if the end of the stream is reached.
   1.779 +     * @throws  IOException If an I/O error has occurred.
   1.780 +     */
   1.781 +    public int read() throws IOException {
   1.782 +        return bin.read();
   1.783 +    }
   1.784 +
   1.785 +    /**
   1.786 +     * Reads into an array of bytes.  This method will block until some input
   1.787 +     * is available. Consider using java.io.DataInputStream.readFully to read
   1.788 +     * exactly 'length' bytes.
   1.789 +     *
   1.790 +     * @param   buf the buffer into which the data is read
   1.791 +     * @param   off the start offset of the data
   1.792 +     * @param   len the maximum number of bytes read
   1.793 +     * @return  the actual number of bytes read, -1 is returned when the end of
   1.794 +     *          the stream is reached.
   1.795 +     * @throws  IOException If an I/O error has occurred.
   1.796 +     * @see java.io.DataInputStream#readFully(byte[],int,int)
   1.797 +     */
   1.798 +    public int read(byte[] buf, int off, int len) throws IOException {
   1.799 +        if (buf == null) {
   1.800 +            throw new NullPointerException();
   1.801 +        }
   1.802 +        int endoff = off + len;
   1.803 +        if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) {
   1.804 +            throw new IndexOutOfBoundsException();
   1.805 +        }
   1.806 +        return bin.read(buf, off, len, false);
   1.807 +    }
   1.808 +
   1.809 +    /**
   1.810 +     * Returns the number of bytes that can be read without blocking.
   1.811 +     *
   1.812 +     * @return  the number of available bytes.
   1.813 +     * @throws  IOException if there are I/O errors while reading from the
   1.814 +     *          underlying <code>InputStream</code>
   1.815 +     */
   1.816 +    public int available() throws IOException {
   1.817 +        return bin.available();
   1.818 +    }
   1.819 +
   1.820 +    /**
   1.821 +     * Closes the input stream. Must be called to release any resources
   1.822 +     * associated with the stream.
   1.823 +     *
   1.824 +     * @throws  IOException If an I/O error has occurred.
   1.825 +     */
   1.826 +    public void close() throws IOException {
   1.827 +        /*
   1.828 +         * Even if stream already closed, propagate redundant close to
   1.829 +         * underlying stream to stay consistent with previous implementations.
   1.830 +         */
   1.831 +        closed = true;
   1.832 +        if (depth == 0) {
   1.833 +            clear();
   1.834 +        }
   1.835 +        bin.close();
   1.836 +    }
   1.837 +
   1.838 +    /**
   1.839 +     * Reads in a boolean.
   1.840 +     *
   1.841 +     * @return  the boolean read.
   1.842 +     * @throws  EOFException If end of file is reached.
   1.843 +     * @throws  IOException If other I/O error has occurred.
   1.844 +     */
   1.845 +    public boolean readBoolean() throws IOException {
   1.846 +        return bin.readBoolean();
   1.847 +    }
   1.848 +
   1.849 +    /**
   1.850 +     * Reads an 8 bit byte.
   1.851 +     *
   1.852 +     * @return  the 8 bit byte read.
   1.853 +     * @throws  EOFException If end of file is reached.
   1.854 +     * @throws  IOException If other I/O error has occurred.
   1.855 +     */
   1.856 +    public byte readByte() throws IOException  {
   1.857 +        return bin.readByte();
   1.858 +    }
   1.859 +
   1.860 +    /**
   1.861 +     * Reads an unsigned 8 bit byte.
   1.862 +     *
   1.863 +     * @return  the 8 bit byte read.
   1.864 +     * @throws  EOFException If end of file is reached.
   1.865 +     * @throws  IOException If other I/O error has occurred.
   1.866 +     */
   1.867 +    public int readUnsignedByte()  throws IOException {
   1.868 +        return bin.readUnsignedByte();
   1.869 +    }
   1.870 +
   1.871 +    /**
   1.872 +     * Reads a 16 bit char.
   1.873 +     *
   1.874 +     * @return  the 16 bit char read.
   1.875 +     * @throws  EOFException If end of file is reached.
   1.876 +     * @throws  IOException If other I/O error has occurred.
   1.877 +     */
   1.878 +    public char readChar()  throws IOException {
   1.879 +        return bin.readChar();
   1.880 +    }
   1.881 +
   1.882 +    /**
   1.883 +     * Reads a 16 bit short.
   1.884 +     *
   1.885 +     * @return  the 16 bit short read.
   1.886 +     * @throws  EOFException If end of file is reached.
   1.887 +     * @throws  IOException If other I/O error has occurred.
   1.888 +     */
   1.889 +    public short readShort()  throws IOException {
   1.890 +        return bin.readShort();
   1.891 +    }
   1.892 +
   1.893 +    /**
   1.894 +     * Reads an unsigned 16 bit short.
   1.895 +     *
   1.896 +     * @return  the 16 bit short read.
   1.897 +     * @throws  EOFException If end of file is reached.
   1.898 +     * @throws  IOException If other I/O error has occurred.
   1.899 +     */
   1.900 +    public int readUnsignedShort() throws IOException {
   1.901 +        return bin.readUnsignedShort();
   1.902 +    }
   1.903 +
   1.904 +    /**
   1.905 +     * Reads a 32 bit int.
   1.906 +     *
   1.907 +     * @return  the 32 bit integer read.
   1.908 +     * @throws  EOFException If end of file is reached.
   1.909 +     * @throws  IOException If other I/O error has occurred.
   1.910 +     */
   1.911 +    public int readInt()  throws IOException {
   1.912 +        return bin.readInt();
   1.913 +    }
   1.914 +
   1.915 +    /**
   1.916 +     * Reads a 64 bit long.
   1.917 +     *
   1.918 +     * @return  the read 64 bit long.
   1.919 +     * @throws  EOFException If end of file is reached.
   1.920 +     * @throws  IOException If other I/O error has occurred.
   1.921 +     */
   1.922 +    public long readLong()  throws IOException {
   1.923 +        return bin.readLong();
   1.924 +    }
   1.925 +
   1.926 +    /**
   1.927 +     * Reads a 32 bit float.
   1.928 +     *
   1.929 +     * @return  the 32 bit float read.
   1.930 +     * @throws  EOFException If end of file is reached.
   1.931 +     * @throws  IOException If other I/O error has occurred.
   1.932 +     */
   1.933 +    public float readFloat() throws IOException {
   1.934 +        return bin.readFloat();
   1.935 +    }
   1.936 +
   1.937 +    /**
   1.938 +     * Reads a 64 bit double.
   1.939 +     *
   1.940 +     * @return  the 64 bit double read.
   1.941 +     * @throws  EOFException If end of file is reached.
   1.942 +     * @throws  IOException If other I/O error has occurred.
   1.943 +     */
   1.944 +    public double readDouble() throws IOException {
   1.945 +        return bin.readDouble();
   1.946 +    }
   1.947 +
   1.948 +    /**
   1.949 +     * Reads bytes, blocking until all bytes are read.
   1.950 +     *
   1.951 +     * @param   buf the buffer into which the data is read
   1.952 +     * @throws  EOFException If end of file is reached.
   1.953 +     * @throws  IOException If other I/O error has occurred.
   1.954 +     */
   1.955 +    public void readFully(byte[] buf) throws IOException {
   1.956 +        bin.readFully(buf, 0, buf.length, false);
   1.957 +    }
   1.958 +
   1.959 +    /**
   1.960 +     * Reads bytes, blocking until all bytes are read.
   1.961 +     *
   1.962 +     * @param   buf the buffer into which the data is read
   1.963 +     * @param   off the start offset of the data
   1.964 +     * @param   len the maximum number of bytes to read
   1.965 +     * @throws  EOFException If end of file is reached.
   1.966 +     * @throws  IOException If other I/O error has occurred.
   1.967 +     */
   1.968 +    public void readFully(byte[] buf, int off, int len) throws IOException {
   1.969 +        int endoff = off + len;
   1.970 +        if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) {
   1.971 +            throw new IndexOutOfBoundsException();
   1.972 +        }
   1.973 +        bin.readFully(buf, off, len, false);
   1.974 +    }
   1.975 +
   1.976 +    /**
   1.977 +     * Skips bytes.
   1.978 +     *
   1.979 +     * @param   len the number of bytes to be skipped
   1.980 +     * @return  the actual number of bytes skipped.
   1.981 +     * @throws  IOException If an I/O error has occurred.
   1.982 +     */
   1.983 +    public int skipBytes(int len) throws IOException {
   1.984 +        return bin.skipBytes(len);
   1.985 +    }
   1.986 +
   1.987 +    /**
   1.988 +     * Reads in a line that has been terminated by a \n, \r, \r\n or EOF.
   1.989 +     *
   1.990 +     * @return  a String copy of the line.
   1.991 +     * @throws  IOException if there are I/O errors while reading from the
   1.992 +     *          underlying <code>InputStream</code>
   1.993 +     * @deprecated This method does not properly convert bytes to characters.
   1.994 +     *          see DataInputStream for the details and alternatives.
   1.995 +     */
   1.996 +    @Deprecated
   1.997 +    public String readLine() throws IOException {
   1.998 +        return bin.readLine();
   1.999 +    }
  1.1000 +
  1.1001 +    /**
  1.1002 +     * Reads a String in
  1.1003 +     * <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
  1.1004 +     * format.
  1.1005 +     *
  1.1006 +     * @return  the String.
  1.1007 +     * @throws  IOException if there are I/O errors while reading from the
  1.1008 +     *          underlying <code>InputStream</code>
  1.1009 +     * @throws  UTFDataFormatException if read bytes do not represent a valid
  1.1010 +     *          modified UTF-8 encoding of a string
  1.1011 +     */
  1.1012 +    public String readUTF() throws IOException {
  1.1013 +        return bin.readUTF();
  1.1014 +    }
  1.1015 +
  1.1016 +    /**
  1.1017 +     * Provide access to the persistent fields read from the input stream.
  1.1018 +     */
  1.1019 +    public static abstract class GetField {
  1.1020 +
  1.1021 +        /**
  1.1022 +         * Get the ObjectStreamClass that describes the fields in the stream.
  1.1023 +         *
  1.1024 +         * @return  the descriptor class that describes the serializable fields
  1.1025 +         */
  1.1026 +        public abstract ObjectStreamClass getObjectStreamClass();
  1.1027 +
  1.1028 +        /**
  1.1029 +         * Return true if the named field is defaulted and has no value in this
  1.1030 +         * stream.
  1.1031 +         *
  1.1032 +         * @param  name the name of the field
  1.1033 +         * @return true, if and only if the named field is defaulted
  1.1034 +         * @throws IOException if there are I/O errors while reading from
  1.1035 +         *         the underlying <code>InputStream</code>
  1.1036 +         * @throws IllegalArgumentException if <code>name</code> does not
  1.1037 +         *         correspond to a serializable field
  1.1038 +         */
  1.1039 +        public abstract boolean defaulted(String name) throws IOException;
  1.1040 +
  1.1041 +        /**
  1.1042 +         * Get the value of the named boolean field from the persistent field.
  1.1043 +         *
  1.1044 +         * @param  name the name of the field
  1.1045 +         * @param  val the default value to use if <code>name</code> does not
  1.1046 +         *         have a value
  1.1047 +         * @return the value of the named <code>boolean</code> field
  1.1048 +         * @throws IOException if there are I/O errors while reading from the
  1.1049 +         *         underlying <code>InputStream</code>
  1.1050 +         * @throws IllegalArgumentException if type of <code>name</code> is
  1.1051 +         *         not serializable or if the field type is incorrect
  1.1052 +         */
  1.1053 +        public abstract boolean get(String name, boolean val)
  1.1054 +            throws IOException;
  1.1055 +
  1.1056 +        /**
  1.1057 +         * Get the value of the named byte field from the persistent field.
  1.1058 +         *
  1.1059 +         * @param  name the name of the field
  1.1060 +         * @param  val the default value to use if <code>name</code> does not
  1.1061 +         *         have a value
  1.1062 +         * @return the value of the named <code>byte</code> field
  1.1063 +         * @throws IOException if there are I/O errors while reading from the
  1.1064 +         *         underlying <code>InputStream</code>
  1.1065 +         * @throws IllegalArgumentException if type of <code>name</code> is
  1.1066 +         *         not serializable or if the field type is incorrect
  1.1067 +         */
  1.1068 +        public abstract byte get(String name, byte val) throws IOException;
  1.1069 +
  1.1070 +        /**
  1.1071 +         * Get the value of the named char field from the persistent field.
  1.1072 +         *
  1.1073 +         * @param  name the name of the field
  1.1074 +         * @param  val the default value to use if <code>name</code> does not
  1.1075 +         *         have a value
  1.1076 +         * @return the value of the named <code>char</code> field
  1.1077 +         * @throws IOException if there are I/O errors while reading from the
  1.1078 +         *         underlying <code>InputStream</code>
  1.1079 +         * @throws IllegalArgumentException if type of <code>name</code> is
  1.1080 +         *         not serializable or if the field type is incorrect
  1.1081 +         */
  1.1082 +        public abstract char get(String name, char val) throws IOException;
  1.1083 +
  1.1084 +        /**
  1.1085 +         * Get the value of the named short field from the persistent field.
  1.1086 +         *
  1.1087 +         * @param  name the name of the field
  1.1088 +         * @param  val the default value to use if <code>name</code> does not
  1.1089 +         *         have a value
  1.1090 +         * @return the value of the named <code>short</code> field
  1.1091 +         * @throws IOException if there are I/O errors while reading from the
  1.1092 +         *         underlying <code>InputStream</code>
  1.1093 +         * @throws IllegalArgumentException if type of <code>name</code> is
  1.1094 +         *         not serializable or if the field type is incorrect
  1.1095 +         */
  1.1096 +        public abstract short get(String name, short val) throws IOException;
  1.1097 +
  1.1098 +        /**
  1.1099 +         * Get the value of the named int field from the persistent field.
  1.1100 +         *
  1.1101 +         * @param  name the name of the field
  1.1102 +         * @param  val the default value to use if <code>name</code> does not
  1.1103 +         *         have a value
  1.1104 +         * @return the value of the named <code>int</code> field
  1.1105 +         * @throws IOException if there are I/O errors while reading from the
  1.1106 +         *         underlying <code>InputStream</code>
  1.1107 +         * @throws IllegalArgumentException if type of <code>name</code> is
  1.1108 +         *         not serializable or if the field type is incorrect
  1.1109 +         */
  1.1110 +        public abstract int get(String name, int val) throws IOException;
  1.1111 +
  1.1112 +        /**
  1.1113 +         * Get the value of the named long field from the persistent field.
  1.1114 +         *
  1.1115 +         * @param  name the name of the field
  1.1116 +         * @param  val the default value to use if <code>name</code> does not
  1.1117 +         *         have a value
  1.1118 +         * @return the value of the named <code>long</code> field
  1.1119 +         * @throws IOException if there are I/O errors while reading from the
  1.1120 +         *         underlying <code>InputStream</code>
  1.1121 +         * @throws IllegalArgumentException if type of <code>name</code> is
  1.1122 +         *         not serializable or if the field type is incorrect
  1.1123 +         */
  1.1124 +        public abstract long get(String name, long val) throws IOException;
  1.1125 +
  1.1126 +        /**
  1.1127 +         * Get the value of the named float field from the persistent field.
  1.1128 +         *
  1.1129 +         * @param  name the name of the field
  1.1130 +         * @param  val the default value to use if <code>name</code> does not
  1.1131 +         *         have a value
  1.1132 +         * @return the value of the named <code>float</code> field
  1.1133 +         * @throws IOException if there are I/O errors while reading from the
  1.1134 +         *         underlying <code>InputStream</code>
  1.1135 +         * @throws IllegalArgumentException if type of <code>name</code> is
  1.1136 +         *         not serializable or if the field type is incorrect
  1.1137 +         */
  1.1138 +        public abstract float get(String name, float val) throws IOException;
  1.1139 +
  1.1140 +        /**
  1.1141 +         * Get the value of the named double field from the persistent field.
  1.1142 +         *
  1.1143 +         * @param  name the name of the field
  1.1144 +         * @param  val the default value to use if <code>name</code> does not
  1.1145 +         *         have a value
  1.1146 +         * @return the value of the named <code>double</code> field
  1.1147 +         * @throws IOException if there are I/O errors while reading from the
  1.1148 +         *         underlying <code>InputStream</code>
  1.1149 +         * @throws IllegalArgumentException if type of <code>name</code> is
  1.1150 +         *         not serializable or if the field type is incorrect
  1.1151 +         */
  1.1152 +        public abstract double get(String name, double val) throws IOException;
  1.1153 +
  1.1154 +        /**
  1.1155 +         * Get the value of the named Object field from the persistent field.
  1.1156 +         *
  1.1157 +         * @param  name the name of the field
  1.1158 +         * @param  val the default value to use if <code>name</code> does not
  1.1159 +         *         have a value
  1.1160 +         * @return the value of the named <code>Object</code> field
  1.1161 +         * @throws IOException if there are I/O errors while reading from the
  1.1162 +         *         underlying <code>InputStream</code>
  1.1163 +         * @throws IllegalArgumentException if type of <code>name</code> is
  1.1164 +         *         not serializable or if the field type is incorrect
  1.1165 +         */
  1.1166 +        public abstract Object get(String name, Object val) throws IOException;
  1.1167 +    }
  1.1168 +
  1.1169 +    /**
  1.1170 +     * Verifies that this (possibly subclass) instance can be constructed
  1.1171 +     * without violating security constraints: the subclass must not override
  1.1172 +     * security-sensitive non-final methods, or else the
  1.1173 +     * "enableSubclassImplementation" SerializablePermission is checked.
  1.1174 +     */
  1.1175 +    private void verifySubclass() {
  1.1176 +        Class cl = getClass();
  1.1177 +        if (cl == ObjectInputStream.class) {
  1.1178 +            return;
  1.1179 +        }
  1.1180 +        throw new SecurityException();
  1.1181 +    }
  1.1182 +
  1.1183 +    /**
  1.1184 +     * Clears internal data structures.
  1.1185 +     */
  1.1186 +    private void clear() {
  1.1187 +        handles.clear();
  1.1188 +        vlist.clear();
  1.1189 +    }
  1.1190 +
  1.1191 +    /**
  1.1192 +     * Underlying readObject implementation.
  1.1193 +     */
  1.1194 +    private Object readObject0(boolean unshared) throws IOException {
  1.1195 +        boolean oldMode = bin.getBlockDataMode();
  1.1196 +        if (oldMode) {
  1.1197 +            int remain = bin.currentBlockRemaining();
  1.1198 +            if (remain > 0) {
  1.1199 +                throw new OptionalDataException(remain);
  1.1200 +            } else if (defaultDataEnd) {
  1.1201 +                /*
  1.1202 +                 * Fix for 4360508: stream is currently at the end of a field
  1.1203 +                 * value block written via default serialization; since there
  1.1204 +                 * is no terminating TC_ENDBLOCKDATA tag, simulate
  1.1205 +                 * end-of-custom-data behavior explicitly.
  1.1206 +                 */
  1.1207 +                throw new OptionalDataException(true);
  1.1208 +            }
  1.1209 +            bin.setBlockDataMode(false);
  1.1210 +        }
  1.1211 +
  1.1212 +        byte tc;
  1.1213 +        while ((tc = bin.peekByte()) == TC_RESET) {
  1.1214 +            bin.readByte();
  1.1215 +            handleReset();
  1.1216 +        }
  1.1217 +
  1.1218 +        depth++;
  1.1219 +        try {
  1.1220 +            switch (tc) {
  1.1221 +                case TC_NULL:
  1.1222 +                    return readNull();
  1.1223 +
  1.1224 +                case TC_REFERENCE:
  1.1225 +                    return readHandle(unshared);
  1.1226 +
  1.1227 +                case TC_CLASS:
  1.1228 +                    return readClass(unshared);
  1.1229 +
  1.1230 +                case TC_CLASSDESC:
  1.1231 +                case TC_PROXYCLASSDESC:
  1.1232 +                    return readClassDesc(unshared);
  1.1233 +
  1.1234 +                case TC_STRING:
  1.1235 +                case TC_LONGSTRING:
  1.1236 +                    return checkResolve(readString(unshared));
  1.1237 +
  1.1238 +                case TC_ARRAY:
  1.1239 +                    return checkResolve(readArray(unshared));
  1.1240 +
  1.1241 +                case TC_ENUM:
  1.1242 +                    return checkResolve(readEnum(unshared));
  1.1243 +
  1.1244 +                case TC_OBJECT:
  1.1245 +                    return checkResolve(readOrdinaryObject(unshared));
  1.1246 +
  1.1247 +                case TC_EXCEPTION:
  1.1248 +                    IOException ex = readFatalException();
  1.1249 +                    throw new WriteAbortedException("writing aborted", ex);
  1.1250 +
  1.1251 +                case TC_BLOCKDATA:
  1.1252 +                case TC_BLOCKDATALONG:
  1.1253 +                    if (oldMode) {
  1.1254 +                        bin.setBlockDataMode(true);
  1.1255 +                        bin.peek();             // force header read
  1.1256 +                        throw new OptionalDataException(
  1.1257 +                            bin.currentBlockRemaining());
  1.1258 +                    } else {
  1.1259 +                        throw new StreamCorruptedException(
  1.1260 +                            "unexpected block data");
  1.1261 +                    }
  1.1262 +
  1.1263 +                case TC_ENDBLOCKDATA:
  1.1264 +                    if (oldMode) {
  1.1265 +                        throw new OptionalDataException(true);
  1.1266 +                    } else {
  1.1267 +                        throw new StreamCorruptedException(
  1.1268 +                            "unexpected end of block data");
  1.1269 +                    }
  1.1270 +
  1.1271 +                default:
  1.1272 +                    throw new StreamCorruptedException(
  1.1273 +                        String.format("invalid type code: %02X", tc));
  1.1274 +            }
  1.1275 +        } finally {
  1.1276 +            depth--;
  1.1277 +            bin.setBlockDataMode(oldMode);
  1.1278 +        }
  1.1279 +    }
  1.1280 +
  1.1281 +    /**
  1.1282 +     * If resolveObject has been enabled and given object does not have an
  1.1283 +     * exception associated with it, calls resolveObject to determine
  1.1284 +     * replacement for object, and updates handle table accordingly.  Returns
  1.1285 +     * replacement object, or echoes provided object if no replacement
  1.1286 +     * occurred.  Expects that passHandle is set to given object's handle prior
  1.1287 +     * to calling this method.
  1.1288 +     */
  1.1289 +    private Object checkResolve(Object obj) throws IOException {
  1.1290 +        if (!enableResolve || handles.lookupException(passHandle) != null) {
  1.1291 +            return obj;
  1.1292 +        }
  1.1293 +        Object rep = resolveObject(obj);
  1.1294 +        if (rep != obj) {
  1.1295 +            handles.setObject(passHandle, rep);
  1.1296 +        }
  1.1297 +        return rep;
  1.1298 +    }
  1.1299 +
  1.1300 +    /**
  1.1301 +     * Reads string without allowing it to be replaced in stream.  Called from
  1.1302 +     * within ObjectStreamClass.read().
  1.1303 +     */
  1.1304 +    String readTypeString() throws IOException {
  1.1305 +        int oldHandle = passHandle;
  1.1306 +        try {
  1.1307 +            byte tc = bin.peekByte();
  1.1308 +            switch (tc) {
  1.1309 +                case TC_NULL:
  1.1310 +                    return (String) readNull();
  1.1311 +
  1.1312 +                case TC_REFERENCE:
  1.1313 +                    return (String) readHandle(false);
  1.1314 +
  1.1315 +                case TC_STRING:
  1.1316 +                case TC_LONGSTRING:
  1.1317 +                    return readString(false);
  1.1318 +
  1.1319 +                default:
  1.1320 +                    throw new StreamCorruptedException(
  1.1321 +                        String.format("invalid type code: %02X", tc));
  1.1322 +            }
  1.1323 +        } finally {
  1.1324 +            passHandle = oldHandle;
  1.1325 +        }
  1.1326 +    }
  1.1327 +
  1.1328 +    /**
  1.1329 +     * Reads in null code, sets passHandle to NULL_HANDLE and returns null.
  1.1330 +     */
  1.1331 +    private Object readNull() throws IOException {
  1.1332 +        if (bin.readByte() != TC_NULL) {
  1.1333 +            throw new InternalError();
  1.1334 +        }
  1.1335 +        passHandle = NULL_HANDLE;
  1.1336 +        return null;
  1.1337 +    }
  1.1338 +
  1.1339 +    /**
  1.1340 +     * Reads in object handle, sets passHandle to the read handle, and returns
  1.1341 +     * object associated with the handle.
  1.1342 +     */
  1.1343 +    private Object readHandle(boolean unshared) throws IOException {
  1.1344 +        if (bin.readByte() != TC_REFERENCE) {
  1.1345 +            throw new InternalError();
  1.1346 +        }
  1.1347 +        passHandle = bin.readInt() - baseWireHandle;
  1.1348 +        if (passHandle < 0 || passHandle >= handles.size()) {
  1.1349 +            throw new StreamCorruptedException(
  1.1350 +                String.format("invalid handle value: %08X", passHandle +
  1.1351 +                baseWireHandle));
  1.1352 +        }
  1.1353 +        if (unshared) {
  1.1354 +            // REMIND: what type of exception to throw here?
  1.1355 +            throw new InvalidObjectException(
  1.1356 +                "cannot read back reference as unshared");
  1.1357 +        }
  1.1358 +
  1.1359 +        Object obj = handles.lookupObject(passHandle);
  1.1360 +        if (obj == unsharedMarker) {
  1.1361 +            // REMIND: what type of exception to throw here?
  1.1362 +            throw new InvalidObjectException(
  1.1363 +                "cannot read back reference to unshared object");
  1.1364 +        }
  1.1365 +        return obj;
  1.1366 +    }
  1.1367 +
  1.1368 +    /**
  1.1369 +     * Reads in and returns class object.  Sets passHandle to class object's
  1.1370 +     * assigned handle.  Returns null if class is unresolvable (in which case a
  1.1371 +     * ClassNotFoundException will be associated with the class' handle in the
  1.1372 +     * handle table).
  1.1373 +     */
  1.1374 +    private Class readClass(boolean unshared) throws IOException {
  1.1375 +        if (bin.readByte() != TC_CLASS) {
  1.1376 +            throw new InternalError();
  1.1377 +        }
  1.1378 +        ObjectStreamClass desc = readClassDesc(false);
  1.1379 +        Class cl = desc.forClass();
  1.1380 +        passHandle = handles.assign(unshared ? unsharedMarker : cl);
  1.1381 +
  1.1382 +        ClassNotFoundException resolveEx = desc.getResolveException();
  1.1383 +        if (resolveEx != null) {
  1.1384 +            handles.markException(passHandle, resolveEx);
  1.1385 +        }
  1.1386 +
  1.1387 +        handles.finish(passHandle);
  1.1388 +        return cl;
  1.1389 +    }
  1.1390 +
  1.1391 +    /**
  1.1392 +     * Reads in and returns (possibly null) class descriptor.  Sets passHandle
  1.1393 +     * to class descriptor's assigned handle.  If class descriptor cannot be
  1.1394 +     * resolved to a class in the local VM, a ClassNotFoundException is
  1.1395 +     * associated with the class descriptor's handle.
  1.1396 +     */
  1.1397 +    private ObjectStreamClass readClassDesc(boolean unshared)
  1.1398 +        throws IOException
  1.1399 +    {
  1.1400 +        byte tc = bin.peekByte();
  1.1401 +        switch (tc) {
  1.1402 +            case TC_NULL:
  1.1403 +                return (ObjectStreamClass) readNull();
  1.1404 +
  1.1405 +            case TC_REFERENCE:
  1.1406 +                return (ObjectStreamClass) readHandle(unshared);
  1.1407 +
  1.1408 +            case TC_PROXYCLASSDESC:
  1.1409 +                return readProxyDesc(unshared);
  1.1410 +
  1.1411 +            case TC_CLASSDESC:
  1.1412 +                return readNonProxyDesc(unshared);
  1.1413 +
  1.1414 +            default:
  1.1415 +                throw new StreamCorruptedException(
  1.1416 +                    String.format("invalid type code: %02X", tc));
  1.1417 +        }
  1.1418 +    }
  1.1419 +
  1.1420 +    /**
  1.1421 +     * Reads in and returns class descriptor for a dynamic proxy class.  Sets
  1.1422 +     * passHandle to proxy class descriptor's assigned handle.  If proxy class
  1.1423 +     * descriptor cannot be resolved to a class in the local VM, a
  1.1424 +     * ClassNotFoundException is associated with the descriptor's handle.
  1.1425 +     */
  1.1426 +    private ObjectStreamClass readProxyDesc(boolean unshared)
  1.1427 +        throws IOException
  1.1428 +    {
  1.1429 +        if (bin.readByte() != TC_PROXYCLASSDESC) {
  1.1430 +            throw new InternalError();
  1.1431 +        }
  1.1432 +
  1.1433 +        ObjectStreamClass desc = new ObjectStreamClass();
  1.1434 +        int descHandle = handles.assign(unshared ? unsharedMarker : desc);
  1.1435 +        passHandle = NULL_HANDLE;
  1.1436 +
  1.1437 +        int numIfaces = bin.readInt();
  1.1438 +        String[] ifaces = new String[numIfaces];
  1.1439 +        for (int i = 0; i < numIfaces; i++) {
  1.1440 +            ifaces[i] = bin.readUTF();
  1.1441 +        }
  1.1442 +
  1.1443 +        Class cl = null;
  1.1444 +        ClassNotFoundException resolveEx = null;
  1.1445 +        bin.setBlockDataMode(true);
  1.1446 +        try {
  1.1447 +            if ((cl = resolveProxyClass(ifaces)) == null) {
  1.1448 +                resolveEx = new ClassNotFoundException("null class");
  1.1449 +            }
  1.1450 +        } catch (ClassNotFoundException ex) {
  1.1451 +            resolveEx = ex;
  1.1452 +        }
  1.1453 +        skipCustomData();
  1.1454 +
  1.1455 +        desc.initProxy(cl, resolveEx, readClassDesc(false));
  1.1456 +
  1.1457 +        handles.finish(descHandle);
  1.1458 +        passHandle = descHandle;
  1.1459 +        return desc;
  1.1460 +    }
  1.1461 +
  1.1462 +    /**
  1.1463 +     * Reads in and returns class descriptor for a class that is not a dynamic
  1.1464 +     * proxy class.  Sets passHandle to class descriptor's assigned handle.  If
  1.1465 +     * class descriptor cannot be resolved to a class in the local VM, a
  1.1466 +     * ClassNotFoundException is associated with the descriptor's handle.
  1.1467 +     */
  1.1468 +    private ObjectStreamClass readNonProxyDesc(boolean unshared)
  1.1469 +        throws IOException
  1.1470 +    {
  1.1471 +        if (bin.readByte() != TC_CLASSDESC) {
  1.1472 +            throw new InternalError();
  1.1473 +        }
  1.1474 +
  1.1475 +        ObjectStreamClass desc = new ObjectStreamClass();
  1.1476 +        int descHandle = handles.assign(unshared ? unsharedMarker : desc);
  1.1477 +        passHandle = NULL_HANDLE;
  1.1478 +
  1.1479 +        ObjectStreamClass readDesc = null;
  1.1480 +        try {
  1.1481 +            readDesc = readClassDescriptor();
  1.1482 +        } catch (ClassNotFoundException ex) {
  1.1483 +            throw (IOException) new InvalidClassException(
  1.1484 +                "failed to read class descriptor").initCause(ex);
  1.1485 +        }
  1.1486 +
  1.1487 +        Class cl = null;
  1.1488 +        ClassNotFoundException resolveEx = null;
  1.1489 +        bin.setBlockDataMode(true);
  1.1490 +        try {
  1.1491 +            if ((cl = resolveClass(readDesc)) == null) {
  1.1492 +                resolveEx = new ClassNotFoundException("null class");
  1.1493 +            }
  1.1494 +        } catch (ClassNotFoundException ex) {
  1.1495 +            resolveEx = ex;
  1.1496 +        }
  1.1497 +        skipCustomData();
  1.1498 +
  1.1499 +        desc.initNonProxy(readDesc, cl, resolveEx, readClassDesc(false));
  1.1500 +
  1.1501 +        handles.finish(descHandle);
  1.1502 +        passHandle = descHandle;
  1.1503 +        return desc;
  1.1504 +    }
  1.1505 +
  1.1506 +    /**
  1.1507 +     * Reads in and returns new string.  Sets passHandle to new string's
  1.1508 +     * assigned handle.
  1.1509 +     */
  1.1510 +    private String readString(boolean unshared) throws IOException {
  1.1511 +        String str;
  1.1512 +        byte tc = bin.readByte();
  1.1513 +        switch (tc) {
  1.1514 +            case TC_STRING:
  1.1515 +                str = bin.readUTF();
  1.1516 +                break;
  1.1517 +
  1.1518 +            case TC_LONGSTRING:
  1.1519 +                str = bin.readLongUTF();
  1.1520 +                break;
  1.1521 +
  1.1522 +            default:
  1.1523 +                throw new StreamCorruptedException(
  1.1524 +                    String.format("invalid type code: %02X", tc));
  1.1525 +        }
  1.1526 +        passHandle = handles.assign(unshared ? unsharedMarker : str);
  1.1527 +        handles.finish(passHandle);
  1.1528 +        return str;
  1.1529 +    }
  1.1530 +
  1.1531 +    /**
  1.1532 +     * Reads in and returns array object, or null if array class is
  1.1533 +     * unresolvable.  Sets passHandle to array's assigned handle.
  1.1534 +     */
  1.1535 +    private Object readArray(boolean unshared) throws IOException {
  1.1536 +        if (bin.readByte() != TC_ARRAY) {
  1.1537 +            throw new InternalError();
  1.1538 +        }
  1.1539 +
  1.1540 +        ObjectStreamClass desc = readClassDesc(false);
  1.1541 +        int len = bin.readInt();
  1.1542 +
  1.1543 +        Object array = null;
  1.1544 +        Class cl, ccl = null;
  1.1545 +        if ((cl = desc.forClass()) != null) {
  1.1546 +            ccl = cl.getComponentType();
  1.1547 +            array = Array.newInstance(ccl, len);
  1.1548 +        }
  1.1549 +
  1.1550 +        int arrayHandle = handles.assign(unshared ? unsharedMarker : array);
  1.1551 +        ClassNotFoundException resolveEx = desc.getResolveException();
  1.1552 +        if (resolveEx != null) {
  1.1553 +            handles.markException(arrayHandle, resolveEx);
  1.1554 +        }
  1.1555 +
  1.1556 +        if (ccl == null) {
  1.1557 +            for (int i = 0; i < len; i++) {
  1.1558 +                readObject0(false);
  1.1559 +            }
  1.1560 +        } else if (ccl.isPrimitive()) {
  1.1561 +            if (ccl == Integer.TYPE) {
  1.1562 +                bin.readInts((int[]) array, 0, len);
  1.1563 +            } else if (ccl == Byte.TYPE) {
  1.1564 +                bin.readFully((byte[]) array, 0, len, true);
  1.1565 +            } else if (ccl == Long.TYPE) {
  1.1566 +                bin.readLongs((long[]) array, 0, len);
  1.1567 +            } else if (ccl == Float.TYPE) {
  1.1568 +                bin.readFloats((float[]) array, 0, len);
  1.1569 +            } else if (ccl == Double.TYPE) {
  1.1570 +                bin.readDoubles((double[]) array, 0, len);
  1.1571 +            } else if (ccl == Short.TYPE) {
  1.1572 +                bin.readShorts((short[]) array, 0, len);
  1.1573 +            } else if (ccl == Character.TYPE) {
  1.1574 +                bin.readChars((char[]) array, 0, len);
  1.1575 +            } else if (ccl == Boolean.TYPE) {
  1.1576 +                bin.readBooleans((boolean[]) array, 0, len);
  1.1577 +            } else {
  1.1578 +                throw new InternalError();
  1.1579 +            }
  1.1580 +        } else {
  1.1581 +            Object[] oa = (Object[]) array;
  1.1582 +            for (int i = 0; i < len; i++) {
  1.1583 +                oa[i] = readObject0(false);
  1.1584 +                handles.markDependency(arrayHandle, passHandle);
  1.1585 +            }
  1.1586 +        }
  1.1587 +
  1.1588 +        handles.finish(arrayHandle);
  1.1589 +        passHandle = arrayHandle;
  1.1590 +        return array;
  1.1591 +    }
  1.1592 +
  1.1593 +    /**
  1.1594 +     * Reads in and returns enum constant, or null if enum type is
  1.1595 +     * unresolvable.  Sets passHandle to enum constant's assigned handle.
  1.1596 +     */
  1.1597 +    private Enum readEnum(boolean unshared) throws IOException {
  1.1598 +        if (bin.readByte() != TC_ENUM) {
  1.1599 +            throw new InternalError();
  1.1600 +        }
  1.1601 +
  1.1602 +        ObjectStreamClass desc = readClassDesc(false);
  1.1603 +        if (!desc.isEnum()) {
  1.1604 +            throw new InvalidClassException("non-enum class: " + desc);
  1.1605 +        }
  1.1606 +
  1.1607 +        int enumHandle = handles.assign(unshared ? unsharedMarker : null);
  1.1608 +        ClassNotFoundException resolveEx = desc.getResolveException();
  1.1609 +        if (resolveEx != null) {
  1.1610 +            handles.markException(enumHandle, resolveEx);
  1.1611 +        }
  1.1612 +
  1.1613 +        String name = readString(false);
  1.1614 +        Enum en = null;
  1.1615 +        Class cl = desc.forClass();
  1.1616 +        if (cl != null) {
  1.1617 +            try {
  1.1618 +                en = Enum.valueOf(cl, name);
  1.1619 +            } catch (IllegalArgumentException ex) {
  1.1620 +                throw (IOException) new InvalidObjectException(
  1.1621 +                    "enum constant " + name + " does not exist in " +
  1.1622 +                    cl).initCause(ex);
  1.1623 +            }
  1.1624 +            if (!unshared) {
  1.1625 +                handles.setObject(enumHandle, en);
  1.1626 +            }
  1.1627 +        }
  1.1628 +
  1.1629 +        handles.finish(enumHandle);
  1.1630 +        passHandle = enumHandle;
  1.1631 +        return en;
  1.1632 +    }
  1.1633 +
  1.1634 +    /**
  1.1635 +     * Reads and returns "ordinary" (i.e., not a String, Class,
  1.1636 +     * ObjectStreamClass, array, or enum constant) object, or null if object's
  1.1637 +     * class is unresolvable (in which case a ClassNotFoundException will be
  1.1638 +     * associated with object's handle).  Sets passHandle to object's assigned
  1.1639 +     * handle.
  1.1640 +     */
  1.1641 +    private Object readOrdinaryObject(boolean unshared)
  1.1642 +        throws IOException
  1.1643 +    {
  1.1644 +        if (bin.readByte() != TC_OBJECT) {
  1.1645 +            throw new InternalError();
  1.1646 +        }
  1.1647 +
  1.1648 +        ObjectStreamClass desc = readClassDesc(false);
  1.1649 +        desc.checkDeserialize();
  1.1650 +
  1.1651 +        Object obj;
  1.1652 +        try {
  1.1653 +            obj = desc.isInstantiable() ? desc.newInstance() : null;
  1.1654 +        } catch (Exception ex) {
  1.1655 +            throw (IOException) new InvalidClassException(
  1.1656 +                desc.forClass().getName(),
  1.1657 +                "unable to create instance").initCause(ex);
  1.1658 +        }
  1.1659 +
  1.1660 +        passHandle = handles.assign(unshared ? unsharedMarker : obj);
  1.1661 +        ClassNotFoundException resolveEx = desc.getResolveException();
  1.1662 +        if (resolveEx != null) {
  1.1663 +            handles.markException(passHandle, resolveEx);
  1.1664 +        }
  1.1665 +
  1.1666 +        if (desc.isExternalizable()) {
  1.1667 +            readExternalData((Externalizable) obj, desc);
  1.1668 +        } else {
  1.1669 +            readSerialData(obj, desc);
  1.1670 +        }
  1.1671 +
  1.1672 +        handles.finish(passHandle);
  1.1673 +
  1.1674 +        if (obj != null &&
  1.1675 +            handles.lookupException(passHandle) == null &&
  1.1676 +            desc.hasReadResolveMethod())
  1.1677 +        {
  1.1678 +            Object rep = desc.invokeReadResolve(obj);
  1.1679 +            if (unshared && rep.getClass().isArray()) {
  1.1680 +                rep = cloneArray(rep);
  1.1681 +            }
  1.1682 +            if (rep != obj) {
  1.1683 +                handles.setObject(passHandle, obj = rep);
  1.1684 +            }
  1.1685 +        }
  1.1686 +
  1.1687 +        return obj;
  1.1688 +    }
  1.1689 +
  1.1690 +    /**
  1.1691 +     * If obj is non-null, reads externalizable data by invoking readExternal()
  1.1692 +     * method of obj; otherwise, attempts to skip over externalizable data.
  1.1693 +     * Expects that passHandle is set to obj's handle before this method is
  1.1694 +     * called.
  1.1695 +     */
  1.1696 +    private void readExternalData(Externalizable obj, ObjectStreamClass desc)
  1.1697 +        throws IOException
  1.1698 +    {
  1.1699 +        Object oldContext = curContext;
  1.1700 +        curContext = null;
  1.1701 +        try {
  1.1702 +            boolean blocked = desc.hasBlockExternalData();
  1.1703 +            if (blocked) {
  1.1704 +                bin.setBlockDataMode(true);
  1.1705 +            }
  1.1706 +            if (obj != null) {
  1.1707 +                try {
  1.1708 +                    obj.readExternal(this);
  1.1709 +                } catch (ClassNotFoundException ex) {
  1.1710 +                    /*
  1.1711 +                     * In most cases, the handle table has already propagated
  1.1712 +                     * a CNFException to passHandle at this point; this mark
  1.1713 +                     * call is included to address cases where the readExternal
  1.1714 +                     * method has cons'ed and thrown a new CNFException of its
  1.1715 +                     * own.
  1.1716 +                     */
  1.1717 +                     handles.markException(passHandle, ex);
  1.1718 +                }
  1.1719 +            }
  1.1720 +            if (blocked) {
  1.1721 +                skipCustomData();
  1.1722 +            }
  1.1723 +        } finally {
  1.1724 +            curContext = oldContext;
  1.1725 +        }
  1.1726 +        /*
  1.1727 +         * At this point, if the externalizable data was not written in
  1.1728 +         * block-data form and either the externalizable class doesn't exist
  1.1729 +         * locally (i.e., obj == null) or readExternal() just threw a
  1.1730 +         * CNFException, then the stream is probably in an inconsistent state,
  1.1731 +         * since some (or all) of the externalizable data may not have been
  1.1732 +         * consumed.  Since there's no "correct" action to take in this case,
  1.1733 +         * we mimic the behavior of past serialization implementations and
  1.1734 +         * blindly hope that the stream is in sync; if it isn't and additional
  1.1735 +         * externalizable data remains in the stream, a subsequent read will
  1.1736 +         * most likely throw a StreamCorruptedException.
  1.1737 +         */
  1.1738 +    }
  1.1739 +
  1.1740 +    /**
  1.1741 +     * Reads (or attempts to skip, if obj is null or is tagged with a
  1.1742 +     * ClassNotFoundException) instance data for each serializable class of
  1.1743 +     * object in stream, from superclass to subclass.  Expects that passHandle
  1.1744 +     * is set to obj's handle before this method is called.
  1.1745 +     */
  1.1746 +    private void readSerialData(Object obj, ObjectStreamClass desc)
  1.1747 +        throws IOException
  1.1748 +    {
  1.1749 +        ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
  1.1750 +        for (int i = 0; i < slots.length; i++) {
  1.1751 +            ObjectStreamClass slotDesc = slots[i].desc;
  1.1752 +
  1.1753 +            if (slots[i].hasData) {
  1.1754 +                if (obj != null &&
  1.1755 +                    slotDesc.hasReadObjectMethod() &&
  1.1756 +                    handles.lookupException(passHandle) == null)
  1.1757 +                {
  1.1758 +                    Object oldContext = curContext;
  1.1759 +
  1.1760 +                    try {
  1.1761 +                        curContext = null; //new SerialCallbackContext(obj, slotDesc);
  1.1762 +
  1.1763 +                        bin.setBlockDataMode(true);
  1.1764 +                        slotDesc.invokeReadObject(obj, this);
  1.1765 +                    } catch (ClassNotFoundException ex) {
  1.1766 +                        /*
  1.1767 +                         * In most cases, the handle table has already
  1.1768 +                         * propagated a CNFException to passHandle at this
  1.1769 +                         * point; this mark call is included to address cases
  1.1770 +                         * where the custom readObject method has cons'ed and
  1.1771 +                         * thrown a new CNFException of its own.
  1.1772 +                         */
  1.1773 +                        handles.markException(passHandle, ex);
  1.1774 +                    } finally {
  1.1775 +                        //curContext.setUsed();
  1.1776 +                        curContext = oldContext;
  1.1777 +                    }
  1.1778 +
  1.1779 +                    /*
  1.1780 +                     * defaultDataEnd may have been set indirectly by custom
  1.1781 +                     * readObject() method when calling defaultReadObject() or
  1.1782 +                     * readFields(); clear it to restore normal read behavior.
  1.1783 +                     */
  1.1784 +                    defaultDataEnd = false;
  1.1785 +                } else {
  1.1786 +                    defaultReadFields(obj, slotDesc);
  1.1787 +                }
  1.1788 +                if (slotDesc.hasWriteObjectData()) {
  1.1789 +                    skipCustomData();
  1.1790 +                } else {
  1.1791 +                    bin.setBlockDataMode(false);
  1.1792 +                }
  1.1793 +            } else {
  1.1794 +                if (obj != null &&
  1.1795 +                    slotDesc.hasReadObjectNoDataMethod() &&
  1.1796 +                    handles.lookupException(passHandle) == null)
  1.1797 +                {
  1.1798 +                    slotDesc.invokeReadObjectNoData(obj);
  1.1799 +                }
  1.1800 +            }
  1.1801 +        }
  1.1802 +    }
  1.1803 +
  1.1804 +    /**
  1.1805 +     * Skips over all block data and objects until TC_ENDBLOCKDATA is
  1.1806 +     * encountered.
  1.1807 +     */
  1.1808 +    private void skipCustomData() throws IOException {
  1.1809 +        int oldHandle = passHandle;
  1.1810 +        for (;;) {
  1.1811 +            if (bin.getBlockDataMode()) {
  1.1812 +                bin.skipBlockData();
  1.1813 +                bin.setBlockDataMode(false);
  1.1814 +            }
  1.1815 +            switch (bin.peekByte()) {
  1.1816 +                case TC_BLOCKDATA:
  1.1817 +                case TC_BLOCKDATALONG:
  1.1818 +                    bin.setBlockDataMode(true);
  1.1819 +                    break;
  1.1820 +
  1.1821 +                case TC_ENDBLOCKDATA:
  1.1822 +                    bin.readByte();
  1.1823 +                    passHandle = oldHandle;
  1.1824 +                    return;
  1.1825 +
  1.1826 +                default:
  1.1827 +                    readObject0(false);
  1.1828 +                    break;
  1.1829 +            }
  1.1830 +        }
  1.1831 +    }
  1.1832 +
  1.1833 +    /**
  1.1834 +     * Reads in values of serializable fields declared by given class
  1.1835 +     * descriptor.  If obj is non-null, sets field values in obj.  Expects that
  1.1836 +     * passHandle is set to obj's handle before this method is called.
  1.1837 +     */
  1.1838 +    private void defaultReadFields(Object obj, ObjectStreamClass desc)
  1.1839 +        throws IOException
  1.1840 +    {
  1.1841 +        // REMIND: is isInstance check necessary?
  1.1842 +        Class cl = desc.forClass();
  1.1843 +        if (cl != null && obj != null && !cl.isInstance(obj)) {
  1.1844 +            throw new ClassCastException();
  1.1845 +        }
  1.1846 +
  1.1847 +        int primDataSize = desc.getPrimDataSize();
  1.1848 +        if (primVals == null || primVals.length < primDataSize) {
  1.1849 +            primVals = new byte[primDataSize];
  1.1850 +        }
  1.1851 +        bin.readFully(primVals, 0, primDataSize, false);
  1.1852 +        if (obj != null) {
  1.1853 +            desc.setPrimFieldValues(obj, primVals);
  1.1854 +        }
  1.1855 +
  1.1856 +        int objHandle = passHandle;
  1.1857 +        ObjectStreamField[] fields = desc.getFields(false);
  1.1858 +        Object[] objVals = new Object[desc.getNumObjFields()];
  1.1859 +        int numPrimFields = fields.length - objVals.length;
  1.1860 +        for (int i = 0; i < objVals.length; i++) {
  1.1861 +            ObjectStreamField f = fields[numPrimFields + i];
  1.1862 +            objVals[i] = readObject0(f.isUnshared());
  1.1863 +            if (f.getField() != null) {
  1.1864 +                handles.markDependency(objHandle, passHandle);
  1.1865 +            }
  1.1866 +        }
  1.1867 +        if (obj != null) {
  1.1868 +            desc.setObjFieldValues(obj, objVals);
  1.1869 +        }
  1.1870 +        passHandle = objHandle;
  1.1871 +    }
  1.1872 +
  1.1873 +    /**
  1.1874 +     * Reads in and returns IOException that caused serialization to abort.
  1.1875 +     * All stream state is discarded prior to reading in fatal exception.  Sets
  1.1876 +     * passHandle to fatal exception's handle.
  1.1877 +     */
  1.1878 +    private IOException readFatalException() throws IOException {
  1.1879 +        if (bin.readByte() != TC_EXCEPTION) {
  1.1880 +            throw new InternalError();
  1.1881 +        }
  1.1882 +        clear();
  1.1883 +        return (IOException) readObject0(false);
  1.1884 +    }
  1.1885 +
  1.1886 +    /**
  1.1887 +     * If recursion depth is 0, clears internal data structures; otherwise,
  1.1888 +     * throws a StreamCorruptedException.  This method is called when a
  1.1889 +     * TC_RESET typecode is encountered.
  1.1890 +     */
  1.1891 +    private void handleReset() throws StreamCorruptedException {
  1.1892 +        if (depth > 0) {
  1.1893 +            throw new StreamCorruptedException(
  1.1894 +                "unexpected reset; recursion depth: " + depth);
  1.1895 +        }
  1.1896 +        clear();
  1.1897 +    }
  1.1898 +
  1.1899 +    /**
  1.1900 +     * Converts specified span of bytes into float values.
  1.1901 +     */
  1.1902 +    // REMIND: remove once hotspot inlines Float.intBitsToFloat
  1.1903 +    private static native void bytesToFloats(byte[] src, int srcpos,
  1.1904 +                                             float[] dst, int dstpos,
  1.1905 +                                             int nfloats);
  1.1906 +
  1.1907 +    /**
  1.1908 +     * Converts specified span of bytes into double values.
  1.1909 +     */
  1.1910 +    // REMIND: remove once hotspot inlines Double.longBitsToDouble
  1.1911 +    private static native void bytesToDoubles(byte[] src, int srcpos,
  1.1912 +                                              double[] dst, int dstpos,
  1.1913 +                                              int ndoubles);
  1.1914 +
  1.1915 +    /**
  1.1916 +     * Returns the first non-null class loader (not counting class loaders of
  1.1917 +     * generated reflection implementation classes) up the execution stack, or
  1.1918 +     * null if only code from the null class loader is on the stack.  This
  1.1919 +     * method is also called via reflection by the following RMI-IIOP class:
  1.1920 +     *
  1.1921 +     *     com.sun.corba.se.internal.util.JDKClassLoader
  1.1922 +     *
  1.1923 +     * This method should not be removed or its signature changed without
  1.1924 +     * corresponding modifications to the above class.
  1.1925 +     */
  1.1926 +    // REMIND: change name to something more accurate?
  1.1927 +    private static native ClassLoader latestUserDefinedLoader();
  1.1928 +
  1.1929 +    /**
  1.1930 +     * Default GetField implementation.
  1.1931 +     */
  1.1932 +    private class GetFieldImpl extends GetField {
  1.1933 +
  1.1934 +        /** class descriptor describing serializable fields */
  1.1935 +        private final ObjectStreamClass desc;
  1.1936 +        /** primitive field values */
  1.1937 +        private final byte[] primVals;
  1.1938 +        /** object field values */
  1.1939 +        private final Object[] objVals;
  1.1940 +        /** object field value handles */
  1.1941 +        private final int[] objHandles;
  1.1942 +
  1.1943 +        /**
  1.1944 +         * Creates GetFieldImpl object for reading fields defined in given
  1.1945 +         * class descriptor.
  1.1946 +         */
  1.1947 +        GetFieldImpl(ObjectStreamClass desc) {
  1.1948 +            this.desc = desc;
  1.1949 +            primVals = new byte[desc.getPrimDataSize()];
  1.1950 +            objVals = new Object[desc.getNumObjFields()];
  1.1951 +            objHandles = new int[objVals.length];
  1.1952 +        }
  1.1953 +
  1.1954 +        public ObjectStreamClass getObjectStreamClass() {
  1.1955 +            return desc;
  1.1956 +        }
  1.1957 +
  1.1958 +        public boolean defaulted(String name) throws IOException {
  1.1959 +            return (getFieldOffset(name, null) < 0);
  1.1960 +        }
  1.1961 +
  1.1962 +        public boolean get(String name, boolean val) throws IOException {
  1.1963 +            int off = getFieldOffset(name, Boolean.TYPE);
  1.1964 +            return (off >= 0) ? Bits.getBoolean(primVals, off) : val;
  1.1965 +        }
  1.1966 +
  1.1967 +        public byte get(String name, byte val) throws IOException {
  1.1968 +            int off = getFieldOffset(name, Byte.TYPE);
  1.1969 +            return (off >= 0) ? primVals[off] : val;
  1.1970 +        }
  1.1971 +
  1.1972 +        public char get(String name, char val) throws IOException {
  1.1973 +            int off = getFieldOffset(name, Character.TYPE);
  1.1974 +            return (off >= 0) ? Bits.getChar(primVals, off) : val;
  1.1975 +        }
  1.1976 +
  1.1977 +        public short get(String name, short val) throws IOException {
  1.1978 +            int off = getFieldOffset(name, Short.TYPE);
  1.1979 +            return (off >= 0) ? Bits.getShort(primVals, off) : val;
  1.1980 +        }
  1.1981 +
  1.1982 +        public int get(String name, int val) throws IOException {
  1.1983 +            int off = getFieldOffset(name, Integer.TYPE);
  1.1984 +            return (off >= 0) ? Bits.getInt(primVals, off) : val;
  1.1985 +        }
  1.1986 +
  1.1987 +        public float get(String name, float val) throws IOException {
  1.1988 +            int off = getFieldOffset(name, Float.TYPE);
  1.1989 +            return (off >= 0) ? Bits.getFloat(primVals, off) : val;
  1.1990 +        }
  1.1991 +
  1.1992 +        public long get(String name, long val) throws IOException {
  1.1993 +            int off = getFieldOffset(name, Long.TYPE);
  1.1994 +            return (off >= 0) ? Bits.getLong(primVals, off) : val;
  1.1995 +        }
  1.1996 +
  1.1997 +        public double get(String name, double val) throws IOException {
  1.1998 +            int off = getFieldOffset(name, Double.TYPE);
  1.1999 +            return (off >= 0) ? Bits.getDouble(primVals, off) : val;
  1.2000 +        }
  1.2001 +
  1.2002 +        public Object get(String name, Object val) throws IOException {
  1.2003 +            int off = getFieldOffset(name, Object.class);
  1.2004 +            if (off >= 0) {
  1.2005 +                int objHandle = objHandles[off];
  1.2006 +                handles.markDependency(passHandle, objHandle);
  1.2007 +                return (handles.lookupException(objHandle) == null) ?
  1.2008 +                    objVals[off] : null;
  1.2009 +            } else {
  1.2010 +                return val;
  1.2011 +            }
  1.2012 +        }
  1.2013 +
  1.2014 +        /**
  1.2015 +         * Reads primitive and object field values from stream.
  1.2016 +         */
  1.2017 +        void readFields() throws IOException {
  1.2018 +            bin.readFully(primVals, 0, primVals.length, false);
  1.2019 +
  1.2020 +            int oldHandle = passHandle;
  1.2021 +            ObjectStreamField[] fields = desc.getFields(false);
  1.2022 +            int numPrimFields = fields.length - objVals.length;
  1.2023 +            for (int i = 0; i < objVals.length; i++) {
  1.2024 +                objVals[i] =
  1.2025 +                    readObject0(fields[numPrimFields + i].isUnshared());
  1.2026 +                objHandles[i] = passHandle;
  1.2027 +            }
  1.2028 +            passHandle = oldHandle;
  1.2029 +        }
  1.2030 +
  1.2031 +        /**
  1.2032 +         * Returns offset of field with given name and type.  A specified type
  1.2033 +         * of null matches all types, Object.class matches all non-primitive
  1.2034 +         * types, and any other non-null type matches assignable types only.
  1.2035 +         * If no matching field is found in the (incoming) class
  1.2036 +         * descriptor but a matching field is present in the associated local
  1.2037 +         * class descriptor, returns -1.  Throws IllegalArgumentException if
  1.2038 +         * neither incoming nor local class descriptor contains a match.
  1.2039 +         */
  1.2040 +        private int getFieldOffset(String name, Class type) {
  1.2041 +            ObjectStreamField field = desc.getField(name, type);
  1.2042 +            if (field != null) {
  1.2043 +                return field.getOffset();
  1.2044 +            } else if (desc.getLocalDesc().getField(name, type) != null) {
  1.2045 +                return -1;
  1.2046 +            } else {
  1.2047 +                throw new IllegalArgumentException("no such field " + name +
  1.2048 +                                                   " with type " + type);
  1.2049 +            }
  1.2050 +        }
  1.2051 +    }
  1.2052 +
  1.2053 +    /**
  1.2054 +     * Prioritized list of callbacks to be performed once object graph has been
  1.2055 +     * completely deserialized.
  1.2056 +     */
  1.2057 +    private static class ValidationList {
  1.2058 +
  1.2059 +
  1.2060 +        /**
  1.2061 +         * Creates new (empty) ValidationList.
  1.2062 +         */
  1.2063 +        ValidationList() {
  1.2064 +        }
  1.2065 +
  1.2066 +        /**
  1.2067 +         * Registers callback.  Throws InvalidObjectException if callback
  1.2068 +         * object is null.
  1.2069 +         */
  1.2070 +        void register(ObjectInputValidation obj, int priority)
  1.2071 +            throws InvalidObjectException
  1.2072 +        {
  1.2073 +            if (obj == null) {
  1.2074 +                throw new InvalidObjectException("null callback");
  1.2075 +            }
  1.2076 +            throw new InvalidObjectException("Does not work.");
  1.2077 +        }
  1.2078 +
  1.2079 +        /**
  1.2080 +         * Invokes all registered callbacks and clears the callback list.
  1.2081 +         * Callbacks with higher priorities are called first; those with equal
  1.2082 +         * priorities may be called in any order.  If any of the callbacks
  1.2083 +         * throws an InvalidObjectException, the callback process is terminated
  1.2084 +         * and the exception propagated upwards.
  1.2085 +         */
  1.2086 +        void doCallbacks() throws InvalidObjectException {
  1.2087 +        }
  1.2088 +
  1.2089 +        /**
  1.2090 +         * Resets the callback list to its initial (empty) state.
  1.2091 +         */
  1.2092 +        public void clear() {
  1.2093 +        }
  1.2094 +    }
  1.2095 +
  1.2096 +    /**
  1.2097 +     * Input stream supporting single-byte peek operations.
  1.2098 +     */
  1.2099 +    private static class PeekInputStream extends InputStream {
  1.2100 +
  1.2101 +        /** underlying stream */
  1.2102 +        private final InputStream in;
  1.2103 +        /** peeked byte */
  1.2104 +        private int peekb = -1;
  1.2105 +
  1.2106 +        /**
  1.2107 +         * Creates new PeekInputStream on top of given underlying stream.
  1.2108 +         */
  1.2109 +        PeekInputStream(InputStream in) {
  1.2110 +            this.in = in;
  1.2111 +        }
  1.2112 +
  1.2113 +        /**
  1.2114 +         * Peeks at next byte value in stream.  Similar to read(), except
  1.2115 +         * that it does not consume the read value.
  1.2116 +         */
  1.2117 +        int peek() throws IOException {
  1.2118 +            return (peekb >= 0) ? peekb : (peekb = in.read());
  1.2119 +        }
  1.2120 +
  1.2121 +        public int read() throws IOException {
  1.2122 +            if (peekb >= 0) {
  1.2123 +                int v = peekb;
  1.2124 +                peekb = -1;
  1.2125 +                return v;
  1.2126 +            } else {
  1.2127 +                return in.read();
  1.2128 +            }
  1.2129 +        }
  1.2130 +
  1.2131 +        public int read(byte[] b, int off, int len) throws IOException {
  1.2132 +            if (len == 0) {
  1.2133 +                return 0;
  1.2134 +            } else if (peekb < 0) {
  1.2135 +                return in.read(b, off, len);
  1.2136 +            } else {
  1.2137 +                b[off++] = (byte) peekb;
  1.2138 +                len--;
  1.2139 +                peekb = -1;
  1.2140 +                int n = in.read(b, off, len);
  1.2141 +                return (n >= 0) ? (n + 1) : 1;
  1.2142 +            }
  1.2143 +        }
  1.2144 +
  1.2145 +        void readFully(byte[] b, int off, int len) throws IOException {
  1.2146 +            int n = 0;
  1.2147 +            while (n < len) {
  1.2148 +                int count = read(b, off + n, len - n);
  1.2149 +                if (count < 0) {
  1.2150 +                    throw new EOFException();
  1.2151 +                }
  1.2152 +                n += count;
  1.2153 +            }
  1.2154 +        }
  1.2155 +
  1.2156 +        public long skip(long n) throws IOException {
  1.2157 +            if (n <= 0) {
  1.2158 +                return 0;
  1.2159 +            }
  1.2160 +            int skipped = 0;
  1.2161 +            if (peekb >= 0) {
  1.2162 +                peekb = -1;
  1.2163 +                skipped++;
  1.2164 +                n--;
  1.2165 +            }
  1.2166 +            return skipped + skip(n);
  1.2167 +        }
  1.2168 +
  1.2169 +        public int available() throws IOException {
  1.2170 +            return in.available() + ((peekb >= 0) ? 1 : 0);
  1.2171 +        }
  1.2172 +
  1.2173 +        public void close() throws IOException {
  1.2174 +            in.close();
  1.2175 +        }
  1.2176 +    }
  1.2177 +
  1.2178 +    /**
  1.2179 +     * Input stream with two modes: in default mode, inputs data written in the
  1.2180 +     * same format as DataOutputStream; in "block data" mode, inputs data
  1.2181 +     * bracketed by block data markers (see object serialization specification
  1.2182 +     * for details).  Buffering depends on block data mode: when in default
  1.2183 +     * mode, no data is buffered in advance; when in block data mode, all data
  1.2184 +     * for the current data block is read in at once (and buffered).
  1.2185 +     */
  1.2186 +    private class BlockDataInputStream
  1.2187 +        extends InputStream implements DataInput
  1.2188 +    {
  1.2189 +        /** maximum data block length */
  1.2190 +        private static final int MAX_BLOCK_SIZE = 1024;
  1.2191 +        /** maximum data block header length */
  1.2192 +        private static final int MAX_HEADER_SIZE = 5;
  1.2193 +        /** (tunable) length of char buffer (for reading strings) */
  1.2194 +        private static final int CHAR_BUF_SIZE = 256;
  1.2195 +        /** readBlockHeader() return value indicating header read may block */
  1.2196 +        private static final int HEADER_BLOCKED = -2;
  1.2197 +
  1.2198 +        /** buffer for reading general/block data */
  1.2199 +        private final byte[] buf = new byte[MAX_BLOCK_SIZE];
  1.2200 +        /** buffer for reading block data headers */
  1.2201 +        private final byte[] hbuf = new byte[MAX_HEADER_SIZE];
  1.2202 +        /** char buffer for fast string reads */
  1.2203 +        private final char[] cbuf = new char[CHAR_BUF_SIZE];
  1.2204 +
  1.2205 +        /** block data mode */
  1.2206 +        private boolean blkmode = false;
  1.2207 +
  1.2208 +        // block data state fields; values meaningful only when blkmode true
  1.2209 +        /** current offset into buf */
  1.2210 +        private int pos = 0;
  1.2211 +        /** end offset of valid data in buf, or -1 if no more block data */
  1.2212 +        private int end = -1;
  1.2213 +        /** number of bytes in current block yet to be read from stream */
  1.2214 +        private int unread = 0;
  1.2215 +
  1.2216 +        /** underlying stream (wrapped in peekable filter stream) */
  1.2217 +        private final PeekInputStream in;
  1.2218 +        /** loopback stream (for data reads that span data blocks) */
  1.2219 +        private final DataInputStream din;
  1.2220 +
  1.2221 +        /**
  1.2222 +         * Creates new BlockDataInputStream on top of given underlying stream.
  1.2223 +         * Block data mode is turned off by default.
  1.2224 +         */
  1.2225 +        BlockDataInputStream(InputStream in) {
  1.2226 +            this.in = new PeekInputStream(in);
  1.2227 +            din = new DataInputStream(this);
  1.2228 +        }
  1.2229 +
  1.2230 +        /**
  1.2231 +         * Sets block data mode to the given mode (true == on, false == off)
  1.2232 +         * and returns the previous mode value.  If the new mode is the same as
  1.2233 +         * the old mode, no action is taken.  Throws IllegalStateException if
  1.2234 +         * block data mode is being switched from on to off while unconsumed
  1.2235 +         * block data is still present in the stream.
  1.2236 +         */
  1.2237 +        boolean setBlockDataMode(boolean newmode) throws IOException {
  1.2238 +            if (blkmode == newmode) {
  1.2239 +                return blkmode;
  1.2240 +            }
  1.2241 +            if (newmode) {
  1.2242 +                pos = 0;
  1.2243 +                end = 0;
  1.2244 +                unread = 0;
  1.2245 +            } else if (pos < end) {
  1.2246 +                throw new IllegalStateException("unread block data");
  1.2247 +            }
  1.2248 +            blkmode = newmode;
  1.2249 +            return !blkmode;
  1.2250 +        }
  1.2251 +
  1.2252 +        /**
  1.2253 +         * Returns true if the stream is currently in block data mode, false
  1.2254 +         * otherwise.
  1.2255 +         */
  1.2256 +        boolean getBlockDataMode() {
  1.2257 +            return blkmode;
  1.2258 +        }
  1.2259 +
  1.2260 +        /**
  1.2261 +         * If in block data mode, skips to the end of the current group of data
  1.2262 +         * blocks (but does not unset block data mode).  If not in block data
  1.2263 +         * mode, throws an IllegalStateException.
  1.2264 +         */
  1.2265 +        void skipBlockData() throws IOException {
  1.2266 +            if (!blkmode) {
  1.2267 +                throw new IllegalStateException("not in block data mode");
  1.2268 +            }
  1.2269 +            while (end >= 0) {
  1.2270 +                refill();
  1.2271 +            }
  1.2272 +        }
  1.2273 +
  1.2274 +        /**
  1.2275 +         * Attempts to read in the next block data header (if any).  If
  1.2276 +         * canBlock is false and a full header cannot be read without possibly
  1.2277 +         * blocking, returns HEADER_BLOCKED, else if the next element in the
  1.2278 +         * stream is a block data header, returns the block data length
  1.2279 +         * specified by the header, else returns -1.
  1.2280 +         */
  1.2281 +        private int readBlockHeader(boolean canBlock) throws IOException {
  1.2282 +            if (defaultDataEnd) {
  1.2283 +                /*
  1.2284 +                 * Fix for 4360508: stream is currently at the end of a field
  1.2285 +                 * value block written via default serialization; since there
  1.2286 +                 * is no terminating TC_ENDBLOCKDATA tag, simulate
  1.2287 +                 * end-of-custom-data behavior explicitly.
  1.2288 +                 */
  1.2289 +                return -1;
  1.2290 +            }
  1.2291 +            try {
  1.2292 +                for (;;) {
  1.2293 +                    int avail = canBlock ? Integer.MAX_VALUE : in.available();
  1.2294 +                    if (avail == 0) {
  1.2295 +                        return HEADER_BLOCKED;
  1.2296 +                    }
  1.2297 +
  1.2298 +                    int tc = in.peek();
  1.2299 +                    switch (tc) {
  1.2300 +                        case TC_BLOCKDATA:
  1.2301 +                            if (avail < 2) {
  1.2302 +                                return HEADER_BLOCKED;
  1.2303 +                            }
  1.2304 +                            in.readFully(hbuf, 0, 2);
  1.2305 +                            return hbuf[1] & 0xFF;
  1.2306 +
  1.2307 +                        case TC_BLOCKDATALONG:
  1.2308 +                            if (avail < 5) {
  1.2309 +                                return HEADER_BLOCKED;
  1.2310 +                            }
  1.2311 +                            in.readFully(hbuf, 0, 5);
  1.2312 +                            int len = Bits.getInt(hbuf, 1);
  1.2313 +                            if (len < 0) {
  1.2314 +                                throw new StreamCorruptedException(
  1.2315 +                                    "illegal block data header length: " +
  1.2316 +                                    len);
  1.2317 +                            }
  1.2318 +                            return len;
  1.2319 +
  1.2320 +                        /*
  1.2321 +                         * TC_RESETs may occur in between data blocks.
  1.2322 +                         * Unfortunately, this case must be parsed at a lower
  1.2323 +                         * level than other typecodes, since primitive data
  1.2324 +                         * reads may span data blocks separated by a TC_RESET.
  1.2325 +                         */
  1.2326 +                        case TC_RESET:
  1.2327 +                            in.read();
  1.2328 +                            handleReset();
  1.2329 +                            break;
  1.2330 +
  1.2331 +                        default:
  1.2332 +                            if (tc >= 0 && (tc < TC_BASE || tc > TC_MAX)) {
  1.2333 +                                throw new StreamCorruptedException(
  1.2334 +                                    String.format("invalid type code: %02X",
  1.2335 +                                    tc));
  1.2336 +                            }
  1.2337 +                            return -1;
  1.2338 +                    }
  1.2339 +                }
  1.2340 +            } catch (EOFException ex) {
  1.2341 +                throw new StreamCorruptedException(
  1.2342 +                    "unexpected EOF while reading block data header");
  1.2343 +            }
  1.2344 +        }
  1.2345 +
  1.2346 +        /**
  1.2347 +         * Refills internal buffer buf with block data.  Any data in buf at the
  1.2348 +         * time of the call is considered consumed.  Sets the pos, end, and
  1.2349 +         * unread fields to reflect the new amount of available block data; if
  1.2350 +         * the next element in the stream is not a data block, sets pos and
  1.2351 +         * unread to 0 and end to -1.
  1.2352 +         */
  1.2353 +        private void refill() throws IOException {
  1.2354 +            try {
  1.2355 +                do {
  1.2356 +                    pos = 0;
  1.2357 +                    if (unread > 0) {
  1.2358 +                        int n =
  1.2359 +                            in.read(buf, 0, Math.min(unread, MAX_BLOCK_SIZE));
  1.2360 +                        if (n >= 0) {
  1.2361 +                            end = n;
  1.2362 +                            unread -= n;
  1.2363 +                        } else {
  1.2364 +                            throw new StreamCorruptedException(
  1.2365 +                                "unexpected EOF in middle of data block");
  1.2366 +                        }
  1.2367 +                    } else {
  1.2368 +                        int n = readBlockHeader(true);
  1.2369 +                        if (n >= 0) {
  1.2370 +                            end = 0;
  1.2371 +                            unread = n;
  1.2372 +                        } else {
  1.2373 +                            end = -1;
  1.2374 +                            unread = 0;
  1.2375 +                        }
  1.2376 +                    }
  1.2377 +                } while (pos == end);
  1.2378 +            } catch (IOException ex) {
  1.2379 +                pos = 0;
  1.2380 +                end = -1;
  1.2381 +                unread = 0;
  1.2382 +                throw ex;
  1.2383 +            }
  1.2384 +        }
  1.2385 +
  1.2386 +        /**
  1.2387 +         * If in block data mode, returns the number of unconsumed bytes
  1.2388 +         * remaining in the current data block.  If not in block data mode,
  1.2389 +         * throws an IllegalStateException.
  1.2390 +         */
  1.2391 +        int currentBlockRemaining() {
  1.2392 +            if (blkmode) {
  1.2393 +                return (end >= 0) ? (end - pos) + unread : 0;
  1.2394 +            } else {
  1.2395 +                throw new IllegalStateException();
  1.2396 +            }
  1.2397 +        }
  1.2398 +
  1.2399 +        /**
  1.2400 +         * Peeks at (but does not consume) and returns the next byte value in
  1.2401 +         * the stream, or -1 if the end of the stream/block data (if in block
  1.2402 +         * data mode) has been reached.
  1.2403 +         */
  1.2404 +        int peek() throws IOException {
  1.2405 +            if (blkmode) {
  1.2406 +                if (pos == end) {
  1.2407 +                    refill();
  1.2408 +                }
  1.2409 +                return (end >= 0) ? (buf[pos] & 0xFF) : -1;
  1.2410 +            } else {
  1.2411 +                return in.peek();
  1.2412 +            }
  1.2413 +        }
  1.2414 +
  1.2415 +        /**
  1.2416 +         * Peeks at (but does not consume) and returns the next byte value in
  1.2417 +         * the stream, or throws EOFException if end of stream/block data has
  1.2418 +         * been reached.
  1.2419 +         */
  1.2420 +        byte peekByte() throws IOException {
  1.2421 +            int val = peek();
  1.2422 +            if (val < 0) {
  1.2423 +                throw new EOFException();
  1.2424 +            }
  1.2425 +            return (byte) val;
  1.2426 +        }
  1.2427 +
  1.2428 +
  1.2429 +        /* ----------------- generic input stream methods ------------------ */
  1.2430 +        /*
  1.2431 +         * The following methods are equivalent to their counterparts in
  1.2432 +         * InputStream, except that they interpret data block boundaries and
  1.2433 +         * read the requested data from within data blocks when in block data
  1.2434 +         * mode.
  1.2435 +         */
  1.2436 +
  1.2437 +        public int read() throws IOException {
  1.2438 +            if (blkmode) {
  1.2439 +                if (pos == end) {
  1.2440 +                    refill();
  1.2441 +                }
  1.2442 +                return (end >= 0) ? (buf[pos++] & 0xFF) : -1;
  1.2443 +            } else {
  1.2444 +                return in.read();
  1.2445 +            }
  1.2446 +        }
  1.2447 +
  1.2448 +        public int read(byte[] b, int off, int len) throws IOException {
  1.2449 +            return read(b, off, len, false);
  1.2450 +        }
  1.2451 +
  1.2452 +        public long skip(long len) throws IOException {
  1.2453 +            long remain = len;
  1.2454 +            while (remain > 0) {
  1.2455 +                if (blkmode) {
  1.2456 +                    if (pos == end) {
  1.2457 +                        refill();
  1.2458 +                    }
  1.2459 +                    if (end < 0) {
  1.2460 +                        break;
  1.2461 +                    }
  1.2462 +                    int nread = (int) Math.min(remain, end - pos);
  1.2463 +                    remain -= nread;
  1.2464 +                    pos += nread;
  1.2465 +                } else {
  1.2466 +                    int nread = (int) Math.min(remain, MAX_BLOCK_SIZE);
  1.2467 +                    if ((nread = in.read(buf, 0, nread)) < 0) {
  1.2468 +                        break;
  1.2469 +                    }
  1.2470 +                    remain -= nread;
  1.2471 +                }
  1.2472 +            }
  1.2473 +            return len - remain;
  1.2474 +        }
  1.2475 +
  1.2476 +        public int available() throws IOException {
  1.2477 +            if (blkmode) {
  1.2478 +                if ((pos == end) && (unread == 0)) {
  1.2479 +                    int n;
  1.2480 +                    while ((n = readBlockHeader(false)) == 0) ;
  1.2481 +                    switch (n) {
  1.2482 +                        case HEADER_BLOCKED:
  1.2483 +                            break;
  1.2484 +
  1.2485 +                        case -1:
  1.2486 +                            pos = 0;
  1.2487 +                            end = -1;
  1.2488 +                            break;
  1.2489 +
  1.2490 +                        default:
  1.2491 +                            pos = 0;
  1.2492 +                            end = 0;
  1.2493 +                            unread = n;
  1.2494 +                            break;
  1.2495 +                    }
  1.2496 +                }
  1.2497 +                // avoid unnecessary call to in.available() if possible
  1.2498 +                int unreadAvail = (unread > 0) ?
  1.2499 +                    Math.min(in.available(), unread) : 0;
  1.2500 +                return (end >= 0) ? (end - pos) + unreadAvail : 0;
  1.2501 +            } else {
  1.2502 +                return in.available();
  1.2503 +            }
  1.2504 +        }
  1.2505 +
  1.2506 +        public void close() throws IOException {
  1.2507 +            if (blkmode) {
  1.2508 +                pos = 0;
  1.2509 +                end = -1;
  1.2510 +                unread = 0;
  1.2511 +            }
  1.2512 +            in.close();
  1.2513 +        }
  1.2514 +
  1.2515 +        /**
  1.2516 +         * Attempts to read len bytes into byte array b at offset off.  Returns
  1.2517 +         * the number of bytes read, or -1 if the end of stream/block data has
  1.2518 +         * been reached.  If copy is true, reads values into an intermediate
  1.2519 +         * buffer before copying them to b (to avoid exposing a reference to
  1.2520 +         * b).
  1.2521 +         */
  1.2522 +        int read(byte[] b, int off, int len, boolean copy) throws IOException {
  1.2523 +            if (len == 0) {
  1.2524 +                return 0;
  1.2525 +            } else if (blkmode) {
  1.2526 +                if (pos == end) {
  1.2527 +                    refill();
  1.2528 +                }
  1.2529 +                if (end < 0) {
  1.2530 +                    return -1;
  1.2531 +                }
  1.2532 +                int nread = Math.min(len, end - pos);
  1.2533 +                System.arraycopy(buf, pos, b, off, nread);
  1.2534 +                pos += nread;
  1.2535 +                return nread;
  1.2536 +            } else if (copy) {
  1.2537 +                int nread = in.read(buf, 0, Math.min(len, MAX_BLOCK_SIZE));
  1.2538 +                if (nread > 0) {
  1.2539 +                    System.arraycopy(buf, 0, b, off, nread);
  1.2540 +                }
  1.2541 +                return nread;
  1.2542 +            } else {
  1.2543 +                return in.read(b, off, len);
  1.2544 +            }
  1.2545 +        }
  1.2546 +
  1.2547 +        /* ----------------- primitive data input methods ------------------ */
  1.2548 +        /*
  1.2549 +         * The following methods are equivalent to their counterparts in
  1.2550 +         * DataInputStream, except that they interpret data block boundaries
  1.2551 +         * and read the requested data from within data blocks when in block
  1.2552 +         * data mode.
  1.2553 +         */
  1.2554 +
  1.2555 +        public void readFully(byte[] b) throws IOException {
  1.2556 +            readFully(b, 0, b.length, false);
  1.2557 +        }
  1.2558 +
  1.2559 +        public void readFully(byte[] b, int off, int len) throws IOException {
  1.2560 +            readFully(b, off, len, false);
  1.2561 +        }
  1.2562 +
  1.2563 +        public void readFully(byte[] b, int off, int len, boolean copy)
  1.2564 +            throws IOException
  1.2565 +        {
  1.2566 +            while (len > 0) {
  1.2567 +                int n = read(b, off, len, copy);
  1.2568 +                if (n < 0) {
  1.2569 +                    throw new EOFException();
  1.2570 +                }
  1.2571 +                off += n;
  1.2572 +                len -= n;
  1.2573 +            }
  1.2574 +        }
  1.2575 +
  1.2576 +        public int skipBytes(int n) throws IOException {
  1.2577 +            return din.skipBytes(n);
  1.2578 +        }
  1.2579 +
  1.2580 +        public boolean readBoolean() throws IOException {
  1.2581 +            int v = read();
  1.2582 +            if (v < 0) {
  1.2583 +                throw new EOFException();
  1.2584 +            }
  1.2585 +            return (v != 0);
  1.2586 +        }
  1.2587 +
  1.2588 +        public byte readByte() throws IOException {
  1.2589 +            int v = read();
  1.2590 +            if (v < 0) {
  1.2591 +                throw new EOFException();
  1.2592 +            }
  1.2593 +            return (byte) v;
  1.2594 +        }
  1.2595 +
  1.2596 +        public int readUnsignedByte() throws IOException {
  1.2597 +            int v = read();
  1.2598 +            if (v < 0) {
  1.2599 +                throw new EOFException();
  1.2600 +            }
  1.2601 +            return v;
  1.2602 +        }
  1.2603 +
  1.2604 +        public char readChar() throws IOException {
  1.2605 +            if (!blkmode) {
  1.2606 +                pos = 0;
  1.2607 +                in.readFully(buf, 0, 2);
  1.2608 +            } else if (end - pos < 2) {
  1.2609 +                return din.readChar();
  1.2610 +            }
  1.2611 +            char v = Bits.getChar(buf, pos);
  1.2612 +            pos += 2;
  1.2613 +            return v;
  1.2614 +        }
  1.2615 +
  1.2616 +        public short readShort() throws IOException {
  1.2617 +            if (!blkmode) {
  1.2618 +                pos = 0;
  1.2619 +                in.readFully(buf, 0, 2);
  1.2620 +            } else if (end - pos < 2) {
  1.2621 +                return din.readShort();
  1.2622 +            }
  1.2623 +            short v = Bits.getShort(buf, pos);
  1.2624 +            pos += 2;
  1.2625 +            return v;
  1.2626 +        }
  1.2627 +
  1.2628 +        public int readUnsignedShort() throws IOException {
  1.2629 +            if (!blkmode) {
  1.2630 +                pos = 0;
  1.2631 +                in.readFully(buf, 0, 2);
  1.2632 +            } else if (end - pos < 2) {
  1.2633 +                return din.readUnsignedShort();
  1.2634 +            }
  1.2635 +            int v = Bits.getShort(buf, pos) & 0xFFFF;
  1.2636 +            pos += 2;
  1.2637 +            return v;
  1.2638 +        }
  1.2639 +
  1.2640 +        public int readInt() throws IOException {
  1.2641 +            if (!blkmode) {
  1.2642 +                pos = 0;
  1.2643 +                in.readFully(buf, 0, 4);
  1.2644 +            } else if (end - pos < 4) {
  1.2645 +                return din.readInt();
  1.2646 +            }
  1.2647 +            int v = Bits.getInt(buf, pos);
  1.2648 +            pos += 4;
  1.2649 +            return v;
  1.2650 +        }
  1.2651 +
  1.2652 +        public float readFloat() throws IOException {
  1.2653 +            if (!blkmode) {
  1.2654 +                pos = 0;
  1.2655 +                in.readFully(buf, 0, 4);
  1.2656 +            } else if (end - pos < 4) {
  1.2657 +                return din.readFloat();
  1.2658 +            }
  1.2659 +            float v = Bits.getFloat(buf, pos);
  1.2660 +            pos += 4;
  1.2661 +            return v;
  1.2662 +        }
  1.2663 +
  1.2664 +        public long readLong() throws IOException {
  1.2665 +            if (!blkmode) {
  1.2666 +                pos = 0;
  1.2667 +                in.readFully(buf, 0, 8);
  1.2668 +            } else if (end - pos < 8) {
  1.2669 +                return din.readLong();
  1.2670 +            }
  1.2671 +            long v = Bits.getLong(buf, pos);
  1.2672 +            pos += 8;
  1.2673 +            return v;
  1.2674 +        }
  1.2675 +
  1.2676 +        public double readDouble() throws IOException {
  1.2677 +            if (!blkmode) {
  1.2678 +                pos = 0;
  1.2679 +                in.readFully(buf, 0, 8);
  1.2680 +            } else if (end - pos < 8) {
  1.2681 +                return din.readDouble();
  1.2682 +            }
  1.2683 +            double v = Bits.getDouble(buf, pos);
  1.2684 +            pos += 8;
  1.2685 +            return v;
  1.2686 +        }
  1.2687 +
  1.2688 +        public String readUTF() throws IOException {
  1.2689 +            return readUTFBody(readUnsignedShort());
  1.2690 +        }
  1.2691 +
  1.2692 +        public String readLine() throws IOException {
  1.2693 +            return din.readLine();      // deprecated, not worth optimizing
  1.2694 +        }
  1.2695 +
  1.2696 +        /* -------------- primitive data array input methods --------------- */
  1.2697 +        /*
  1.2698 +         * The following methods read in spans of primitive data values.
  1.2699 +         * Though equivalent to calling the corresponding primitive read
  1.2700 +         * methods repeatedly, these methods are optimized for reading groups
  1.2701 +         * of primitive data values more efficiently.
  1.2702 +         */
  1.2703 +
  1.2704 +        void readBooleans(boolean[] v, int off, int len) throws IOException {
  1.2705 +            int stop, endoff = off + len;
  1.2706 +            while (off < endoff) {
  1.2707 +                if (!blkmode) {
  1.2708 +                    int span = Math.min(endoff - off, MAX_BLOCK_SIZE);
  1.2709 +                    in.readFully(buf, 0, span);
  1.2710 +                    stop = off + span;
  1.2711 +                    pos = 0;
  1.2712 +                } else if (end - pos < 1) {
  1.2713 +                    v[off++] = din.readBoolean();
  1.2714 +                    continue;
  1.2715 +                } else {
  1.2716 +                    stop = Math.min(endoff, off + end - pos);
  1.2717 +                }
  1.2718 +
  1.2719 +                while (off < stop) {
  1.2720 +                    v[off++] = Bits.getBoolean(buf, pos++);
  1.2721 +                }
  1.2722 +            }
  1.2723 +        }
  1.2724 +
  1.2725 +        void readChars(char[] v, int off, int len) throws IOException {
  1.2726 +            int stop, endoff = off + len;
  1.2727 +            while (off < endoff) {
  1.2728 +                if (!blkmode) {
  1.2729 +                    int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 1);
  1.2730 +                    in.readFully(buf, 0, span << 1);
  1.2731 +                    stop = off + span;
  1.2732 +                    pos = 0;
  1.2733 +                } else if (end - pos < 2) {
  1.2734 +                    v[off++] = din.readChar();
  1.2735 +                    continue;
  1.2736 +                } else {
  1.2737 +                    stop = Math.min(endoff, off + ((end - pos) >> 1));
  1.2738 +                }
  1.2739 +
  1.2740 +                while (off < stop) {
  1.2741 +                    v[off++] = Bits.getChar(buf, pos);
  1.2742 +                    pos += 2;
  1.2743 +                }
  1.2744 +            }
  1.2745 +        }
  1.2746 +
  1.2747 +        void readShorts(short[] v, int off, int len) throws IOException {
  1.2748 +            int stop, endoff = off + len;
  1.2749 +            while (off < endoff) {
  1.2750 +                if (!blkmode) {
  1.2751 +                    int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 1);
  1.2752 +                    in.readFully(buf, 0, span << 1);
  1.2753 +                    stop = off + span;
  1.2754 +                    pos = 0;
  1.2755 +                } else if (end - pos < 2) {
  1.2756 +                    v[off++] = din.readShort();
  1.2757 +                    continue;
  1.2758 +                } else {
  1.2759 +                    stop = Math.min(endoff, off + ((end - pos) >> 1));
  1.2760 +                }
  1.2761 +
  1.2762 +                while (off < stop) {
  1.2763 +                    v[off++] = Bits.getShort(buf, pos);
  1.2764 +                    pos += 2;
  1.2765 +                }
  1.2766 +            }
  1.2767 +        }
  1.2768 +
  1.2769 +        void readInts(int[] v, int off, int len) throws IOException {
  1.2770 +            int stop, endoff = off + len;
  1.2771 +            while (off < endoff) {
  1.2772 +                if (!blkmode) {
  1.2773 +                    int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 2);
  1.2774 +                    in.readFully(buf, 0, span << 2);
  1.2775 +                    stop = off + span;
  1.2776 +                    pos = 0;
  1.2777 +                } else if (end - pos < 4) {
  1.2778 +                    v[off++] = din.readInt();
  1.2779 +                    continue;
  1.2780 +                } else {
  1.2781 +                    stop = Math.min(endoff, off + ((end - pos) >> 2));
  1.2782 +                }
  1.2783 +
  1.2784 +                while (off < stop) {
  1.2785 +                    v[off++] = Bits.getInt(buf, pos);
  1.2786 +                    pos += 4;
  1.2787 +                }
  1.2788 +            }
  1.2789 +        }
  1.2790 +
  1.2791 +        void readFloats(float[] v, int off, int len) throws IOException {
  1.2792 +            int span, endoff = off + len;
  1.2793 +            while (off < endoff) {
  1.2794 +                if (!blkmode) {
  1.2795 +                    span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 2);
  1.2796 +                    in.readFully(buf, 0, span << 2);
  1.2797 +                    pos = 0;
  1.2798 +                } else if (end - pos < 4) {
  1.2799 +                    v[off++] = din.readFloat();
  1.2800 +                    continue;
  1.2801 +                } else {
  1.2802 +                    span = Math.min(endoff - off, ((end - pos) >> 2));
  1.2803 +                }
  1.2804 +
  1.2805 +                bytesToFloats(buf, pos, v, off, span);
  1.2806 +                off += span;
  1.2807 +                pos += span << 2;
  1.2808 +            }
  1.2809 +        }
  1.2810 +
  1.2811 +        void readLongs(long[] v, int off, int len) throws IOException {
  1.2812 +            int stop, endoff = off + len;
  1.2813 +            while (off < endoff) {
  1.2814 +                if (!blkmode) {
  1.2815 +                    int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 3);
  1.2816 +                    in.readFully(buf, 0, span << 3);
  1.2817 +                    stop = off + span;
  1.2818 +                    pos = 0;
  1.2819 +                } else if (end - pos < 8) {
  1.2820 +                    v[off++] = din.readLong();
  1.2821 +                    continue;
  1.2822 +                } else {
  1.2823 +                    stop = Math.min(endoff, off + ((end - pos) >> 3));
  1.2824 +                }
  1.2825 +
  1.2826 +                while (off < stop) {
  1.2827 +                    v[off++] = Bits.getLong(buf, pos);
  1.2828 +                    pos += 8;
  1.2829 +                }
  1.2830 +            }
  1.2831 +        }
  1.2832 +
  1.2833 +        void readDoubles(double[] v, int off, int len) throws IOException {
  1.2834 +            int span, endoff = off + len;
  1.2835 +            while (off < endoff) {
  1.2836 +                if (!blkmode) {
  1.2837 +                    span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 3);
  1.2838 +                    in.readFully(buf, 0, span << 3);
  1.2839 +                    pos = 0;
  1.2840 +                } else if (end - pos < 8) {
  1.2841 +                    v[off++] = din.readDouble();
  1.2842 +                    continue;
  1.2843 +                } else {
  1.2844 +                    span = Math.min(endoff - off, ((end - pos) >> 3));
  1.2845 +                }
  1.2846 +
  1.2847 +                bytesToDoubles(buf, pos, v, off, span);
  1.2848 +                off += span;
  1.2849 +                pos += span << 3;
  1.2850 +            }
  1.2851 +        }
  1.2852 +
  1.2853 +        /**
  1.2854 +         * Reads in string written in "long" UTF format.  "Long" UTF format is
  1.2855 +         * identical to standard UTF, except that it uses an 8 byte header
  1.2856 +         * (instead of the standard 2 bytes) to convey the UTF encoding length.
  1.2857 +         */
  1.2858 +        String readLongUTF() throws IOException {
  1.2859 +            return readUTFBody(readLong());
  1.2860 +        }
  1.2861 +
  1.2862 +        /**
  1.2863 +         * Reads in the "body" (i.e., the UTF representation minus the 2-byte
  1.2864 +         * or 8-byte length header) of a UTF encoding, which occupies the next
  1.2865 +         * utflen bytes.
  1.2866 +         */
  1.2867 +        private String readUTFBody(long utflen) throws IOException {
  1.2868 +            StringBuilder sbuf = new StringBuilder();
  1.2869 +            if (!blkmode) {
  1.2870 +                end = pos = 0;
  1.2871 +            }
  1.2872 +
  1.2873 +            while (utflen > 0) {
  1.2874 +                int avail = end - pos;
  1.2875 +                if (avail >= 3 || (long) avail == utflen) {
  1.2876 +                    utflen -= readUTFSpan(sbuf, utflen);
  1.2877 +                } else {
  1.2878 +                    if (blkmode) {
  1.2879 +                        // near block boundary, read one byte at a time
  1.2880 +                        utflen -= readUTFChar(sbuf, utflen);
  1.2881 +                    } else {
  1.2882 +                        // shift and refill buffer manually
  1.2883 +                        if (avail > 0) {
  1.2884 +                            System.arraycopy(buf, pos, buf, 0, avail);
  1.2885 +                        }
  1.2886 +                        pos = 0;
  1.2887 +                        end = (int) Math.min(MAX_BLOCK_SIZE, utflen);
  1.2888 +                        in.readFully(buf, avail, end - avail);
  1.2889 +                    }
  1.2890 +                }
  1.2891 +            }
  1.2892 +
  1.2893 +            return sbuf.toString();
  1.2894 +        }
  1.2895 +
  1.2896 +        /**
  1.2897 +         * Reads span of UTF-encoded characters out of internal buffer
  1.2898 +         * (starting at offset pos and ending at or before offset end),
  1.2899 +         * consuming no more than utflen bytes.  Appends read characters to
  1.2900 +         * sbuf.  Returns the number of bytes consumed.
  1.2901 +         */
  1.2902 +        private long readUTFSpan(StringBuilder sbuf, long utflen)
  1.2903 +            throws IOException
  1.2904 +        {
  1.2905 +            int cpos = 0;
  1.2906 +            int start = pos;
  1.2907 +            int avail = Math.min(end - pos, CHAR_BUF_SIZE);
  1.2908 +            // stop short of last char unless all of utf bytes in buffer
  1.2909 +            int stop = pos + ((utflen > avail) ? avail - 2 : (int) utflen);
  1.2910 +            boolean outOfBounds = false;
  1.2911 +
  1.2912 +            try {
  1.2913 +                while (pos < stop) {
  1.2914 +                    int b1, b2, b3;
  1.2915 +                    b1 = buf[pos++] & 0xFF;
  1.2916 +                    switch (b1 >> 4) {
  1.2917 +                        case 0:
  1.2918 +                        case 1:
  1.2919 +                        case 2:
  1.2920 +                        case 3:
  1.2921 +                        case 4:
  1.2922 +                        case 5:
  1.2923 +                        case 6:
  1.2924 +                        case 7:   // 1 byte format: 0xxxxxxx
  1.2925 +                            cbuf[cpos++] = (char) b1;
  1.2926 +                            break;
  1.2927 +
  1.2928 +                        case 12:
  1.2929 +                        case 13:  // 2 byte format: 110xxxxx 10xxxxxx
  1.2930 +                            b2 = buf[pos++];
  1.2931 +                            if ((b2 & 0xC0) != 0x80) {
  1.2932 +                                throw new UTFDataFormatException();
  1.2933 +                            }
  1.2934 +                            cbuf[cpos++] = (char) (((b1 & 0x1F) << 6) |
  1.2935 +                                                   ((b2 & 0x3F) << 0));
  1.2936 +                            break;
  1.2937 +
  1.2938 +                        case 14:  // 3 byte format: 1110xxxx 10xxxxxx 10xxxxxx
  1.2939 +                            b3 = buf[pos + 1];
  1.2940 +                            b2 = buf[pos + 0];
  1.2941 +                            pos += 2;
  1.2942 +                            if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) {
  1.2943 +                                throw new UTFDataFormatException();
  1.2944 +                            }
  1.2945 +                            cbuf[cpos++] = (char) (((b1 & 0x0F) << 12) |
  1.2946 +                                                   ((b2 & 0x3F) << 6) |
  1.2947 +                                                   ((b3 & 0x3F) << 0));
  1.2948 +                            break;
  1.2949 +
  1.2950 +                        default:  // 10xx xxxx, 1111 xxxx
  1.2951 +                            throw new UTFDataFormatException();
  1.2952 +                    }
  1.2953 +                }
  1.2954 +            } catch (ArrayIndexOutOfBoundsException ex) {
  1.2955 +                outOfBounds = true;
  1.2956 +            } finally {
  1.2957 +                if (outOfBounds || (pos - start) > utflen) {
  1.2958 +                    /*
  1.2959 +                     * Fix for 4450867: if a malformed utf char causes the
  1.2960 +                     * conversion loop to scan past the expected end of the utf
  1.2961 +                     * string, only consume the expected number of utf bytes.
  1.2962 +                     */
  1.2963 +                    pos = start + (int) utflen;
  1.2964 +                    throw new UTFDataFormatException();
  1.2965 +                }
  1.2966 +            }
  1.2967 +
  1.2968 +            sbuf.append(cbuf, 0, cpos);
  1.2969 +            return pos - start;
  1.2970 +        }
  1.2971 +
  1.2972 +        /**
  1.2973 +         * Reads in single UTF-encoded character one byte at a time, appends
  1.2974 +         * the character to sbuf, and returns the number of bytes consumed.
  1.2975 +         * This method is used when reading in UTF strings written in block
  1.2976 +         * data mode to handle UTF-encoded characters which (potentially)
  1.2977 +         * straddle block-data boundaries.
  1.2978 +         */
  1.2979 +        private int readUTFChar(StringBuilder sbuf, long utflen)
  1.2980 +            throws IOException
  1.2981 +        {
  1.2982 +            int b1, b2, b3;
  1.2983 +            b1 = readByte() & 0xFF;
  1.2984 +            switch (b1 >> 4) {
  1.2985 +                case 0:
  1.2986 +                case 1:
  1.2987 +                case 2:
  1.2988 +                case 3:
  1.2989 +                case 4:
  1.2990 +                case 5:
  1.2991 +                case 6:
  1.2992 +                case 7:     // 1 byte format: 0xxxxxxx
  1.2993 +                    sbuf.append((char) b1);
  1.2994 +                    return 1;
  1.2995 +
  1.2996 +                case 12:
  1.2997 +                case 13:    // 2 byte format: 110xxxxx 10xxxxxx
  1.2998 +                    if (utflen < 2) {
  1.2999 +                        throw new UTFDataFormatException();
  1.3000 +                    }
  1.3001 +                    b2 = readByte();
  1.3002 +                    if ((b2 & 0xC0) != 0x80) {
  1.3003 +                        throw new UTFDataFormatException();
  1.3004 +                    }
  1.3005 +                    sbuf.append((char) (((b1 & 0x1F) << 6) |
  1.3006 +                                        ((b2 & 0x3F) << 0)));
  1.3007 +                    return 2;
  1.3008 +
  1.3009 +                case 14:    // 3 byte format: 1110xxxx 10xxxxxx 10xxxxxx
  1.3010 +                    if (utflen < 3) {
  1.3011 +                        if (utflen == 2) {
  1.3012 +                            readByte();         // consume remaining byte
  1.3013 +                        }
  1.3014 +                        throw new UTFDataFormatException();
  1.3015 +                    }
  1.3016 +                    b2 = readByte();
  1.3017 +                    b3 = readByte();
  1.3018 +                    if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) {
  1.3019 +                        throw new UTFDataFormatException();
  1.3020 +                    }
  1.3021 +                    sbuf.append((char) (((b1 & 0x0F) << 12) |
  1.3022 +                                        ((b2 & 0x3F) << 6) |
  1.3023 +                                        ((b3 & 0x3F) << 0)));
  1.3024 +                    return 3;
  1.3025 +
  1.3026 +                default:   // 10xx xxxx, 1111 xxxx
  1.3027 +                    throw new UTFDataFormatException();
  1.3028 +            }
  1.3029 +        }
  1.3030 +    }
  1.3031 +
  1.3032 +    /**
  1.3033 +     * Unsynchronized table which tracks wire handle to object mappings, as
  1.3034 +     * well as ClassNotFoundExceptions associated with deserialized objects.
  1.3035 +     * This class implements an exception-propagation algorithm for
  1.3036 +     * determining which objects should have ClassNotFoundExceptions associated
  1.3037 +     * with them, taking into account cycles and discontinuities (e.g., skipped
  1.3038 +     * fields) in the object graph.
  1.3039 +     *
  1.3040 +     * <p>General use of the table is as follows: during deserialization, a
  1.3041 +     * given object is first assigned a handle by calling the assign method.
  1.3042 +     * This method leaves the assigned handle in an "open" state, wherein
  1.3043 +     * dependencies on the exception status of other handles can be registered
  1.3044 +     * by calling the markDependency method, or an exception can be directly
  1.3045 +     * associated with the handle by calling markException.  When a handle is
  1.3046 +     * tagged with an exception, the HandleTable assumes responsibility for
  1.3047 +     * propagating the exception to any other objects which depend
  1.3048 +     * (transitively) on the exception-tagged object.
  1.3049 +     *
  1.3050 +     * <p>Once all exception information/dependencies for the handle have been
  1.3051 +     * registered, the handle should be "closed" by calling the finish method
  1.3052 +     * on it.  The act of finishing a handle allows the exception propagation
  1.3053 +     * algorithm to aggressively prune dependency links, lessening the
  1.3054 +     * performance/memory impact of exception tracking.
  1.3055 +     *
  1.3056 +     * <p>Note that the exception propagation algorithm used depends on handles
  1.3057 +     * being assigned/finished in LIFO order; however, for simplicity as well
  1.3058 +     * as memory conservation, it does not enforce this constraint.
  1.3059 +     */
  1.3060 +    // REMIND: add full description of exception propagation algorithm?
  1.3061 +    private static class HandleTable {
  1.3062 +
  1.3063 +        /* status codes indicating whether object has associated exception */
  1.3064 +        private static final byte STATUS_OK = 1;
  1.3065 +        private static final byte STATUS_UNKNOWN = 2;
  1.3066 +        private static final byte STATUS_EXCEPTION = 3;
  1.3067 +
  1.3068 +        /** array mapping handle -> object status */
  1.3069 +        byte[] status;
  1.3070 +        /** array mapping handle -> object/exception (depending on status) */
  1.3071 +        Object[] entries;
  1.3072 +        /** array mapping handle -> list of dependent handles (if any) */
  1.3073 +        HandleList[] deps;
  1.3074 +        /** lowest unresolved dependency */
  1.3075 +        int lowDep = -1;
  1.3076 +        /** number of handles in table */
  1.3077 +        int size = 0;
  1.3078 +
  1.3079 +        /**
  1.3080 +         * Creates handle table with the given initial capacity.
  1.3081 +         */
  1.3082 +        HandleTable(int initialCapacity) {
  1.3083 +            status = new byte[initialCapacity];
  1.3084 +            entries = new Object[initialCapacity];
  1.3085 +            deps = new HandleList[initialCapacity];
  1.3086 +        }
  1.3087 +
  1.3088 +        /**
  1.3089 +         * Assigns next available handle to given object, and returns assigned
  1.3090 +         * handle.  Once object has been completely deserialized (and all
  1.3091 +         * dependencies on other objects identified), the handle should be
  1.3092 +         * "closed" by passing it to finish().
  1.3093 +         */
  1.3094 +        int assign(Object obj) {
  1.3095 +            if (size >= entries.length) {
  1.3096 +                grow();
  1.3097 +            }
  1.3098 +            status[size] = STATUS_UNKNOWN;
  1.3099 +            entries[size] = obj;
  1.3100 +            return size++;
  1.3101 +        }
  1.3102 +
  1.3103 +        /**
  1.3104 +         * Registers a dependency (in exception status) of one handle on
  1.3105 +         * another.  The dependent handle must be "open" (i.e., assigned, but
  1.3106 +         * not finished yet).  No action is taken if either dependent or target
  1.3107 +         * handle is NULL_HANDLE.
  1.3108 +         */
  1.3109 +        void markDependency(int dependent, int target) {
  1.3110 +            if (dependent == NULL_HANDLE || target == NULL_HANDLE) {
  1.3111 +                return;
  1.3112 +            }
  1.3113 +            switch (status[dependent]) {
  1.3114 +
  1.3115 +                case STATUS_UNKNOWN:
  1.3116 +                    switch (status[target]) {
  1.3117 +                        case STATUS_OK:
  1.3118 +                            // ignore dependencies on objs with no exception
  1.3119 +                            break;
  1.3120 +
  1.3121 +                        case STATUS_EXCEPTION:
  1.3122 +                            // eagerly propagate exception
  1.3123 +                            markException(dependent,
  1.3124 +                                (ClassNotFoundException) entries[target]);
  1.3125 +                            break;
  1.3126 +
  1.3127 +                        case STATUS_UNKNOWN:
  1.3128 +                            // add to dependency list of target
  1.3129 +                            if (deps[target] == null) {
  1.3130 +                                deps[target] = new HandleList();
  1.3131 +                            }
  1.3132 +                            deps[target].add(dependent);
  1.3133 +
  1.3134 +                            // remember lowest unresolved target seen
  1.3135 +                            if (lowDep < 0 || lowDep > target) {
  1.3136 +                                lowDep = target;
  1.3137 +                            }
  1.3138 +                            break;
  1.3139 +
  1.3140 +                        default:
  1.3141 +                            throw new InternalError();
  1.3142 +                    }
  1.3143 +                    break;
  1.3144 +
  1.3145 +                case STATUS_EXCEPTION:
  1.3146 +                    break;
  1.3147 +
  1.3148 +                default:
  1.3149 +                    throw new InternalError();
  1.3150 +            }
  1.3151 +        }
  1.3152 +
  1.3153 +        /**
  1.3154 +         * Associates a ClassNotFoundException (if one not already associated)
  1.3155 +         * with the currently active handle and propagates it to other
  1.3156 +         * referencing objects as appropriate.  The specified handle must be
  1.3157 +         * "open" (i.e., assigned, but not finished yet).
  1.3158 +         */
  1.3159 +        void markException(int handle, ClassNotFoundException ex) {
  1.3160 +            switch (status[handle]) {
  1.3161 +                case STATUS_UNKNOWN:
  1.3162 +                    status[handle] = STATUS_EXCEPTION;
  1.3163 +                    entries[handle] = ex;
  1.3164 +
  1.3165 +                    // propagate exception to dependents
  1.3166 +                    HandleList dlist = deps[handle];
  1.3167 +                    if (dlist != null) {
  1.3168 +                        int ndeps = dlist.size();
  1.3169 +                        for (int i = 0; i < ndeps; i++) {
  1.3170 +                            markException(dlist.get(i), ex);
  1.3171 +                        }
  1.3172 +                        deps[handle] = null;
  1.3173 +                    }
  1.3174 +                    break;
  1.3175 +
  1.3176 +                case STATUS_EXCEPTION:
  1.3177 +                    break;
  1.3178 +
  1.3179 +                default:
  1.3180 +                    throw new InternalError();
  1.3181 +            }
  1.3182 +        }
  1.3183 +
  1.3184 +        /**
  1.3185 +         * Marks given handle as finished, meaning that no new dependencies
  1.3186 +         * will be marked for handle.  Calls to the assign and finish methods
  1.3187 +         * must occur in LIFO order.
  1.3188 +         */
  1.3189 +        void finish(int handle) {
  1.3190 +            int end;
  1.3191 +            if (lowDep < 0) {
  1.3192 +                // no pending unknowns, only resolve current handle
  1.3193 +                end = handle + 1;
  1.3194 +            } else if (lowDep >= handle) {
  1.3195 +                // pending unknowns now clearable, resolve all upward handles
  1.3196 +                end = size;
  1.3197 +                lowDep = -1;
  1.3198 +            } else {
  1.3199 +                // unresolved backrefs present, can't resolve anything yet
  1.3200 +                return;
  1.3201 +            }
  1.3202 +
  1.3203 +            // change STATUS_UNKNOWN -> STATUS_OK in selected span of handles
  1.3204 +            for (int i = handle; i < end; i++) {
  1.3205 +                switch (status[i]) {
  1.3206 +                    case STATUS_UNKNOWN:
  1.3207 +                        status[i] = STATUS_OK;
  1.3208 +                        deps[i] = null;
  1.3209 +                        break;
  1.3210 +
  1.3211 +                    case STATUS_OK:
  1.3212 +                    case STATUS_EXCEPTION:
  1.3213 +                        break;
  1.3214 +
  1.3215 +                    default:
  1.3216 +                        throw new InternalError();
  1.3217 +                }
  1.3218 +            }
  1.3219 +        }
  1.3220 +
  1.3221 +        /**
  1.3222 +         * Assigns a new object to the given handle.  The object previously
  1.3223 +         * associated with the handle is forgotten.  This method has no effect
  1.3224 +         * if the given handle already has an exception associated with it.
  1.3225 +         * This method may be called at any time after the handle is assigned.
  1.3226 +         */
  1.3227 +        void setObject(int handle, Object obj) {
  1.3228 +            switch (status[handle]) {
  1.3229 +                case STATUS_UNKNOWN:
  1.3230 +                case STATUS_OK:
  1.3231 +                    entries[handle] = obj;
  1.3232 +                    break;
  1.3233 +
  1.3234 +                case STATUS_EXCEPTION:
  1.3235 +                    break;
  1.3236 +
  1.3237 +                default:
  1.3238 +                    throw new InternalError();
  1.3239 +            }
  1.3240 +        }
  1.3241 +
  1.3242 +        /**
  1.3243 +         * Looks up and returns object associated with the given handle.
  1.3244 +         * Returns null if the given handle is NULL_HANDLE, or if it has an
  1.3245 +         * associated ClassNotFoundException.
  1.3246 +         */
  1.3247 +        Object lookupObject(int handle) {
  1.3248 +            return (handle != NULL_HANDLE &&
  1.3249 +                    status[handle] != STATUS_EXCEPTION) ?
  1.3250 +                entries[handle] : null;
  1.3251 +        }
  1.3252 +
  1.3253 +        /**
  1.3254 +         * Looks up and returns ClassNotFoundException associated with the
  1.3255 +         * given handle.  Returns null if the given handle is NULL_HANDLE, or
  1.3256 +         * if there is no ClassNotFoundException associated with the handle.
  1.3257 +         */
  1.3258 +        ClassNotFoundException lookupException(int handle) {
  1.3259 +            return (handle != NULL_HANDLE &&
  1.3260 +                    status[handle] == STATUS_EXCEPTION) ?
  1.3261 +                (ClassNotFoundException) entries[handle] : null;
  1.3262 +        }
  1.3263 +
  1.3264 +        /**
  1.3265 +         * Resets table to its initial state.
  1.3266 +         */
  1.3267 +        void clear() {
  1.3268 +            Arrays.fill(status, 0, size, (byte) 0);
  1.3269 +            Arrays.fill(entries, 0, size, null);
  1.3270 +            Arrays.fill(deps, 0, size, null);
  1.3271 +            lowDep = -1;
  1.3272 +            size = 0;
  1.3273 +        }
  1.3274 +
  1.3275 +        /**
  1.3276 +         * Returns number of handles registered in table.
  1.3277 +         */
  1.3278 +        int size() {
  1.3279 +            return size;
  1.3280 +        }
  1.3281 +
  1.3282 +        /**
  1.3283 +         * Expands capacity of internal arrays.
  1.3284 +         */
  1.3285 +        private void grow() {
  1.3286 +            int newCapacity = (entries.length << 1) + 1;
  1.3287 +
  1.3288 +            byte[] newStatus = new byte[newCapacity];
  1.3289 +            Object[] newEntries = new Object[newCapacity];
  1.3290 +            HandleList[] newDeps = new HandleList[newCapacity];
  1.3291 +
  1.3292 +            System.arraycopy(status, 0, newStatus, 0, size);
  1.3293 +            System.arraycopy(entries, 0, newEntries, 0, size);
  1.3294 +            System.arraycopy(deps, 0, newDeps, 0, size);
  1.3295 +
  1.3296 +            status = newStatus;
  1.3297 +            entries = newEntries;
  1.3298 +            deps = newDeps;
  1.3299 +        }
  1.3300 +
  1.3301 +        /**
  1.3302 +         * Simple growable list of (integer) handles.
  1.3303 +         */
  1.3304 +        private static class HandleList {
  1.3305 +            private int[] list = new int[4];
  1.3306 +            private int size = 0;
  1.3307 +
  1.3308 +            public HandleList() {
  1.3309 +            }
  1.3310 +
  1.3311 +            public void add(int handle) {
  1.3312 +                if (size >= list.length) {
  1.3313 +                    int[] newList = new int[list.length << 1];
  1.3314 +                    System.arraycopy(list, 0, newList, 0, list.length);
  1.3315 +                    list = newList;
  1.3316 +                }
  1.3317 +                list[size++] = handle;
  1.3318 +            }
  1.3319 +
  1.3320 +            public int get(int index) {
  1.3321 +                if (index >= size) {
  1.3322 +                    throw new ArrayIndexOutOfBoundsException();
  1.3323 +                }
  1.3324 +                return list[index];
  1.3325 +            }
  1.3326 +
  1.3327 +            public int size() {
  1.3328 +                return size;
  1.3329 +            }
  1.3330 +        }
  1.3331 +    }
  1.3332 +
  1.3333 +    /**
  1.3334 +     * Method for cloning arrays in case of using unsharing reading
  1.3335 +     */
  1.3336 +    private static Object cloneArray(Object array) {
  1.3337 +        if (array instanceof Object[]) {
  1.3338 +            return ((Object[]) array).clone();
  1.3339 +        } else if (array instanceof boolean[]) {
  1.3340 +            return ((boolean[]) array).clone();
  1.3341 +        } else if (array instanceof byte[]) {
  1.3342 +            return ((byte[]) array).clone();
  1.3343 +        } else if (array instanceof char[]) {
  1.3344 +            return ((char[]) array).clone();
  1.3345 +        } else if (array instanceof double[]) {
  1.3346 +            return ((double[]) array).clone();
  1.3347 +        } else if (array instanceof float[]) {
  1.3348 +            return ((float[]) array).clone();
  1.3349 +        } else if (array instanceof int[]) {
  1.3350 +            return ((int[]) array).clone();
  1.3351 +        } else if (array instanceof long[]) {
  1.3352 +            return ((long[]) array).clone();
  1.3353 +        } else if (array instanceof short[]) {
  1.3354 +            return ((short[]) array).clone();
  1.3355 +        } else {
  1.3356 +            throw new AssertionError();
  1.3357 +        }
  1.3358 +    }
  1.3359 +
  1.3360 +}