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