1 /*
   2  * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.io;
  27 
  28 import java.io.ObjectInputFilter.Config;
  29 import java.io.ObjectStreamClass.ConstructorSupport;
  30 import java.io.ObjectStreamClass.ClassDataSlot;
  31 import java.lang.System.Logger;
  32 import java.lang.invoke.MethodHandle;
  33 import java.lang.reflect.Array;
  34 import java.lang.reflect.InvocationHandler;
  35 import java.lang.reflect.InvocationTargetException;
  36 import java.lang.reflect.Modifier;
  37 import java.lang.reflect.Proxy;
  38 import java.nio.charset.StandardCharsets;
  39 import java.util.Arrays;
  40 import java.util.List;
  41 import java.util.Locale;
  42 import java.util.Objects;
  43 
  44 import jdk.internal.access.JavaLangAccess;
  45 import jdk.internal.access.SharedSecrets;
  46 import jdk.internal.event.DeserializationEvent;
  47 import jdk.internal.misc.Unsafe;
  48 import jdk.internal.util.ByteArray;
  49 
  50 /**
  51  * An ObjectInputStream deserializes primitive data and objects previously
  52  * written using an ObjectOutputStream.
  53  *
  54  * <p><strong>Warning: Deserialization of untrusted data is inherently dangerous
  55  * and should be avoided. Untrusted data should be carefully validated according to the
  56  * "Serialization and Deserialization" section of the
  57  * {@extLink secure_coding_guidelines_javase Secure Coding Guidelines for Java SE}.
  58  * {@extLink serialization_filter_guide Serialization Filtering} describes best
  59  * practices for defensive use of serial filters.
  60  * </strong></p>
  61  *
  62  * <p>The key to disabling deserialization attacks is to prevent instances of
  63  * arbitrary classes from being deserialized, thereby preventing the direct or
  64  * indirect execution of their methods.
  65  * {@link ObjectInputFilter} describes how to use filters and
  66  * {@link ObjectInputFilter.Config} describes how to configure the filter and filter factory.
  67  * Each stream has an optional deserialization filter
  68  * to check the classes and resource limits during deserialization.
  69  * The JVM-wide filter factory ensures that a filter can be set on every {@link ObjectInputStream}
  70  * and every object read from the stream can be checked.
  71  * The {@linkplain #ObjectInputStream() ObjectInputStream constructors} invoke the filter factory
  72  * to select the initial filter which may be updated or replaced by {@link #setObjectInputFilter}.
  73  * <p>
  74  * If an ObjectInputStream has a filter, the {@link ObjectInputFilter} can check that
  75  * the classes, array lengths, number of references in the stream, depth, and
  76  * number of bytes consumed from the input stream are allowed and
  77  * if not, can terminate deserialization.
  78  *
  79  * <p>ObjectOutputStream and ObjectInputStream can provide an application with
  80  * persistent storage for graphs of objects when used with a FileOutputStream
  81  * and FileInputStream respectively.  ObjectInputStream is used to recover
  82  * those objects previously serialized. Other uses include passing objects
  83  * between hosts using a socket stream or for marshaling and unmarshaling
  84  * arguments and parameters in a remote communication system.
  85  *
  86  * <p>ObjectInputStream ensures that the types of all objects in the graph
  87  * created from the stream match the classes present in the Java Virtual
  88  * Machine.  Classes are loaded as required using the standard mechanisms.
  89  *
  90  * <p>Only objects that support the java.io.Serializable or
  91  * java.io.Externalizable interface can be read from streams.
  92  *
  93  * <p>The method {@code readObject} is used to read an object from the
  94  * stream.  Java's safe casting should be used to get the desired type.  In
  95  * Java, strings and arrays are objects and are treated as objects during
  96  * serialization. When read they need to be cast to the expected type.
  97  *
  98  * <p>Primitive data types can be read from the stream using the appropriate
  99  * method on DataInput.
 100  *
 101  * <p>The default deserialization mechanism for objects restores the contents
 102  * of each field to the value and type it had when it was written.  Fields
 103  * declared as transient or static are ignored by the deserialization process.
 104  * References to other objects cause those objects to be read from the stream
 105  * as necessary.  Graphs of objects are restored correctly using a reference
 106  * sharing mechanism.  New objects are always allocated when deserializing,
 107  * which prevents existing objects from being overwritten.
 108  *
 109  * <p>Reading an object is analogous to running the constructors of a new
 110  * object.  Memory is allocated for the object and initialized to zero (NULL).
 111  * No-arg constructors are invoked for the non-serializable classes and then
 112  * the fields of the serializable classes are restored from the stream starting
 113  * with the serializable class closest to java.lang.object and finishing with
 114  * the object's most specific class.
 115  *
 116  * <p>For example to read from a stream as written by the example in
 117  * {@link ObjectOutputStream}:
 118  * <br>
 119  * {@snippet lang="java" :
 120  *     try (FileInputStream fis = new FileInputStream("t.tmp");
 121  *          ObjectInputStream ois = new ObjectInputStream(fis)) {
 122  *         String label = (String) ois.readObject();
 123  *         LocalDateTime dateTime = (LocalDateTime) ois.readObject();
 124  *         // Use label and dateTime
 125  *     } catch (Exception ex) {
 126  *         // handle exception
 127  *     }
 128  * }
 129  *
 130  * <p>Classes control how they are serialized by implementing either the
 131  * java.io.Serializable or java.io.Externalizable interfaces.
 132  *
 133  * <p>Implementing the Serializable interface allows object serialization to
 134  * save and restore the entire state of the object and it allows classes to
 135  * evolve between the time the stream is written and the time it is read.  It
 136  * automatically traverses references between objects, saving and restoring
 137  * entire graphs.
 138  *
 139  * <p>Serializable classes that require special handling during the
 140  * serialization and deserialization process should implement methods
 141  * with the following signatures:
 142  *
 143  * {@snippet lang="java":
 144  *     private void writeObject(java.io.ObjectOutputStream stream)
 145  *         throws IOException;
 146  *     private void readObject(java.io.ObjectInputStream stream)
 147  *         throws IOException, ClassNotFoundException;
 148  *     private void readObjectNoData()
 149  *         throws ObjectStreamException;
 150  * }
 151  *
 152  * <p>The method name, modifiers, return type, and number and type of
 153  * parameters must match exactly for the method to be used by
 154  * serialization or deserialization. The methods should only be
 155  * declared to throw checked exceptions consistent with these
 156  * signatures.
 157  *
 158  * <p>The readObject method is responsible for reading and restoring the state
 159  * of the object for its particular class using data written to the stream by
 160  * the corresponding writeObject method.  The method does not need to concern
 161  * itself with the state belonging to its superclasses or subclasses.  State is
 162  * restored by reading data from the ObjectInputStream for the individual
 163  * fields and making assignments to the appropriate fields of the object.
 164  * Reading primitive data types is supported by DataInput.
 165  *
 166  * <p>Any attempt to read object data which exceeds the boundaries of the
 167  * custom data written by the corresponding writeObject method will cause an
 168  * OptionalDataException to be thrown with an eof field value of true.
 169  * Non-object reads which exceed the end of the allotted data will reflect the
 170  * end of data in the same way that they would indicate the end of the stream:
 171  * bytewise reads will return -1 as the byte read or number of bytes read, and
 172  * primitive reads will throw EOFExceptions.  If there is no corresponding
 173  * writeObject method, then the end of default serialized data marks the end of
 174  * the allotted data.
 175  *
 176  * <p>Primitive and object read calls issued from within a readExternal method
 177  * behave in the same manner--if the stream is already positioned at the end of
 178  * data written by the corresponding writeExternal method, object reads will
 179  * throw OptionalDataExceptions with eof set to true, bytewise reads will
 180  * return -1, and primitive reads will throw EOFExceptions.  Note that this
 181  * behavior does not hold for streams written with the old
 182  * {@code ObjectStreamConstants.PROTOCOL_VERSION_1} protocol, in which the
 183  * end of data written by writeExternal methods is not demarcated, and hence
 184  * cannot be detected.
 185  *
 186  * <p>The readObjectNoData method is responsible for initializing the state of
 187  * the object for its particular class in the event that the serialization
 188  * stream does not list the given class as a superclass of the object being
 189  * deserialized.  This may occur in cases where the receiving party uses a
 190  * different version of the deserialized instance's class than the sending
 191  * party, and the receiver's version extends classes that are not extended by
 192  * the sender's version.  This may also occur if the serialization stream has
 193  * been tampered; hence, readObjectNoData is useful for initializing
 194  * deserialized objects properly despite a "hostile" or incomplete source
 195  * stream.
 196  *
 197  * <p>Serialization does not read or assign values to the fields of any object
 198  * that does not implement the java.io.Serializable interface.  Subclasses of
 199  * Objects that are not serializable can be serializable. In this case the
 200  * non-serializable class must have a no-arg constructor to allow its fields to
 201  * be initialized.  In this case it is the responsibility of the subclass to
 202  * save and restore the state of the non-serializable class. It is frequently
 203  * the case that the fields of that class are accessible (public, package, or
 204  * protected) or that there are get and set methods that can be used to restore
 205  * the state.
 206  *
 207  * <p>Any exception that occurs while deserializing an object will be caught by
 208  * the ObjectInputStream and abort the reading process.
 209  *
 210  * <p>Implementing the Externalizable interface allows the object to assume
 211  * complete control over the contents and format of the object's serialized
 212  * form.  The methods of the Externalizable interface, writeExternal and
 213  * readExternal, are called to save and restore the objects state.  When
 214  * implemented by a class they can write and read their own state using all of
 215  * the methods of ObjectOutput and ObjectInput.  It is the responsibility of
 216  * the objects to handle any versioning that occurs.
 217  * Value objects cannot be `java.io.Externalizable` because value objects are
 218  * immutable and `Externalizable.readExternal` is unable to modify the fields of the value.
 219  *
 220  * <p>Enum constants are deserialized differently than ordinary serializable or
 221  * externalizable objects.  The serialized form of an enum constant consists
 222  * solely of its name; field values of the constant are not transmitted.  To
 223  * deserialize an enum constant, ObjectInputStream reads the constant name from
 224  * the stream; the deserialized constant is then obtained by calling the static
 225  * method {@code Enum.valueOf(Class, String)} with the enum constant's
 226  * base type and the received constant name as arguments.  Like other
 227  * serializable or externalizable objects, enum constants can function as the
 228  * targets of back references appearing subsequently in the serialization
 229  * stream.  The process by which enum constants are deserialized cannot be
 230  * customized: any class-specific readObject, readObjectNoData, and readResolve
 231  * methods defined by enum types are ignored during deserialization.
 232  * Similarly, any serialPersistentFields or serialVersionUID field declarations
 233  * are also ignored--all enum types have a fixed serialVersionUID of 0L.
 234  *
 235  * <a id="record-serialization"></a>
 236  * <p>Records are serialized differently than ordinary serializable or externalizable
 237  * objects. During deserialization the record's canonical constructor is invoked
 238  * to construct the record object. Certain serialization-related methods, such
 239  * as readObject and writeObject, are ignored for serializable records. See
 240  * <a href="{@docRoot}/../specs/serialization/serial-arch.html#serialization-of-records">
 241  * <cite>Java Object Serialization Specification,</cite> Section 1.13,
 242  * "Serialization of Records"</a> for additional information.
 243  *
 244  * <p>Value classes are {@linkplain Serializable} through the use of the serialization proxy pattern.
 245  * See {@linkplain ObjectOutputStream##valueclass-serialization value class serialization} for details.
 246  * When the proxy is deserialized it re-constructs and returns the value object.
 247  *
 248  * @spec serialization/index.html Java Object Serialization Specification
 249  * @author      Mike Warres
 250  * @author      Roger Riggs
 251  * @see java.io.DataInput
 252  * @see java.io.ObjectOutputStream
 253  * @see java.io.Serializable
 254  * @see <a href="{@docRoot}/../specs/serialization/input.html">
 255  *      <cite>Java Object Serialization Specification,</cite> Section 3, "Object Input Classes"</a>
 256  * @since   1.1
 257  */
 258 public class ObjectInputStream
 259     extends InputStream implements ObjectInput, ObjectStreamConstants
 260 {
 261     private static final String TRACE_DEST =
 262             System.getProperty("TRACE");
 263 
 264     static void TRACE(String format, Object... args) {
 265         if (TRACE_DEST != null) {
 266             var ps = "OUT".equals(TRACE_DEST.toUpperCase(Locale.ROOT)) ? System.out : System.err;
 267             ps.println(("TRACE " + format).formatted(args));
 268         }
 269     }
 270 
 271     /** handle value representing null */
 272     private static final int NULL_HANDLE = -1;
 273 
 274     /** marker for unshared objects in internal handle table */
 275     private static final Object unsharedMarker = new Object();
 276 
 277     private static class Caches {
 278 
 279         /**
 280          * Property to permit setting a filter after objects
 281          * have been read.
 282          * See {@link #setObjectInputFilter(ObjectInputFilter)}
 283          */
 284         static final boolean SET_FILTER_AFTER_READ =
 285                 Boolean.getBoolean("jdk.serialSetFilterAfterRead");
 286 
 287         /**
 288          * Property to control {@link GetField#get(String, Object)} conversion of
 289          * {@link ClassNotFoundException} to {@code null}. If set to {@code true}
 290          * {@link GetField#get(String, Object)} returns null otherwise
 291          * throwing {@link ClassNotFoundException}.
 292          */
 293         private static final boolean GETFIELD_CNFE_RETURNS_NULL =
 294                 Boolean.getBoolean("jdk.serialGetFieldCnfeReturnsNull");
 295 
 296         /**
 297          * Property to override the implementation limit on the number
 298          * of interfaces allowed for Proxies. The property value is clamped to 0..65535.
 299          * The maximum number of interfaces allowed for a proxy is limited to 65535 by
 300          * {@link java.lang.reflect.Proxy#newProxyInstance(ClassLoader, Class[], InvocationHandler)}.
 301          */
 302         static final int PROXY_INTERFACE_LIMIT =
 303                 Math.clamp(Integer.getInteger("jdk.serialProxyInterfaceLimit", 65535), 0, 65535);
 304     }
 305 
 306     /*
 307      * Separate class to defer initialization of logging until needed.
 308      */
 309     private static class Logging {
 310         /*
 311          * Logger for ObjectInputFilter results.
 312          * Setup the filter logger if it is set to DEBUG or TRACE.
 313          * (Assuming it will not change).
 314          */
 315         static final System.Logger filterLogger;
 316 
 317         static {
 318             Logger filterLog = System.getLogger("java.io.serialization");
 319             filterLogger = (filterLog.isLoggable(Logger.Level.DEBUG)
 320                     || filterLog.isLoggable(Logger.Level.TRACE)) ? filterLog : null;
 321         }
 322     }
 323 
 324     /** filter stream for handling block data conversion */
 325     private final BlockDataInputStream bin;
 326     /** validation callback list */
 327     private final ValidationList vlist;
 328     /** recursion depth */
 329     private long depth;
 330     /** Total number of references to any type of object, class, enum, proxy, etc. */
 331     private long totalObjectRefs;
 332     /** whether stream is closed */
 333     private boolean closed;
 334 
 335     /** wire handle -> obj/exception map */
 336     private final HandleTable handles;
 337     /** scratch field for passing handle values up/down call stack */
 338     private int passHandle = NULL_HANDLE;
 339     /** flag set when at end of field value block with no TC_ENDBLOCKDATA */
 340     private boolean defaultDataEnd = false;
 341 
 342     /** if true, invoke readObjectOverride() instead of readObject() */
 343     private final boolean enableOverride;
 344     /** if true, invoke resolveObject() */
 345     private boolean enableResolve;
 346 
 347     /**
 348      * Context during upcalls to class-defined readObject methods; holds
 349      * object currently being deserialized and descriptor for current class.
 350      * Null when not during readObject upcall.
 351      */
 352     private SerialCallbackContext curContext;
 353 
 354     /**
 355      * Filter of class descriptors and classes read from the stream;
 356      * may be null.
 357      */
 358     private ObjectInputFilter serialFilter;
 359 
 360     /**
 361      * True if the stream-specific filter has been set; initially false.
 362      */
 363     private boolean streamFilterSet;
 364 
 365     /**
 366      * Creates an ObjectInputStream that reads from the specified InputStream.
 367      * A serialization stream header is read from the stream and verified.
 368      * This constructor will block until the corresponding ObjectOutputStream
 369      * has written and flushed the header.
 370      *
 371      * <p>The constructor initializes the deserialization filter to the filter returned
 372      * by invoking the serial filter factory returned from {@link Config#getSerialFilterFactory()}
 373      * with {@code null} for the current filter
 374      * and the {@linkplain Config#getSerialFilter() static JVM-wide filter} for the requested filter.
 375      * If the serial filter or serial filter factory properties are invalid
 376      * an {@link IllegalStateException} is thrown.
 377      * When the filter factory {@code apply} method is invoked it may throw a runtime exception
 378      * preventing the {@code ObjectInputStream} from being constructed.
 379      *
 380      * @param   in input stream to read from
 381      * @throws  StreamCorruptedException if the stream header is incorrect
 382      * @throws  IOException if an I/O error occurs while reading stream header
 383      * @throws  IllegalStateException if the initialization of {@link ObjectInputFilter.Config}
 384      *          fails due to invalid serial filter or serial filter factory properties.
 385      * @throws  NullPointerException if {@code in} is {@code null}
 386      * @see     ObjectInputStream#ObjectInputStream()
 387      * @see     ObjectInputStream#readFields()
 388      * @see     ObjectOutputStream#ObjectOutputStream(OutputStream)
 389      */
 390     @SuppressWarnings("this-escape")
 391     public ObjectInputStream(InputStream in) throws IOException {
 392         bin = new BlockDataInputStream(in);
 393         handles = new HandleTable(10);
 394         vlist = new ValidationList();
 395         streamFilterSet = false;
 396         serialFilter = Config.getSerialFilterFactorySingleton().apply(null, Config.getSerialFilter());
 397         enableOverride = false;
 398         readStreamHeader();
 399         bin.setBlockDataMode(true);
 400     }
 401 
 402     /**
 403      * Provide a way for subclasses that are completely reimplementing
 404      * ObjectInputStream to not have to allocate private data just used by this
 405      * implementation of ObjectInputStream.
 406      *
 407      * <p>The constructor initializes the deserialization filter to the filter returned
 408      * by invoking the serial filter factory returned from {@link Config#getSerialFilterFactory()}
 409      * with {@code null} for the current filter
 410      * and the {@linkplain Config#getSerialFilter() static JVM-wide filter} for the requested filter.
 411      * If the serial filter or serial filter factory properties are invalid
 412      * an {@link IllegalStateException} is thrown.
 413      * When the filter factory {@code apply} method is invoked it may throw a runtime exception
 414      * preventing the {@code ObjectInputStream} from being constructed.
 415      *
 416      * @throws  IOException if an I/O error occurs while creating this stream
 417      * @throws  IllegalStateException if the initialization of {@link ObjectInputFilter.Config}
 418      *      fails due to invalid serial filter or serial filter factory properties.
 419      */
 420     protected ObjectInputStream() throws IOException {
 421         bin = null;
 422         handles = null;
 423         vlist = null;
 424         streamFilterSet = false;
 425         serialFilter = Config.getSerialFilterFactorySingleton().apply(null, Config.getSerialFilter());
 426         enableOverride = true;
 427     }
 428 
 429     /**
 430      * Read an object from the ObjectInputStream.  The class of the object, the
 431      * signature of the class, and the values of the non-transient and
 432      * non-static fields of the class and all of its supertypes are read.
 433      * Default deserializing for a class can be overridden using the writeObject
 434      * and readObject methods.  Objects referenced by this object are read
 435      * transitively so that a complete equivalent graph of objects is
 436      * reconstructed by readObject.
 437      *
 438      * <p>The root object is completely restored when all of its fields and the
 439      * objects it references are completely restored.  At this point the object
 440      * validation callbacks are executed in order based on their registered
 441      * priorities. The callbacks are registered by objects (in the readObject
 442      * special methods) as they are individually restored.
 443      *
 444      * <p>The deserialization filter, when not {@code null}, is invoked for
 445      * each object (regular or class) read to reconstruct the root object.
 446      * See {@link #setObjectInputFilter(ObjectInputFilter) setObjectInputFilter} for details.
 447      *
 448      * <p>Serialization and deserialization of value classes is described in
 449      * {@linkplain ObjectOutputStream##valueclass-serialization value class serialization}.
 450      *
 451      * @implSpec
 452      * When enabled with {@code --enable-preview}, serialization and deserialization of
 453      * Core Library value classes migrated from pre-JEP 401 identity classes is
 454      * implementation specific.
 455      *
 456      * <p>Exceptions are thrown for problems with the InputStream and for
 457      * classes that should not be deserialized.  All exceptions are fatal to
 458      * the InputStream and leave it in an indeterminate state; it is up to the
 459      * caller to ignore or recover the stream state.
 460      *
 461      * @throws  ClassNotFoundException Class of a serialized object cannot be
 462      *          found.
 463      * @throws  InvalidClassException Something is wrong with a class used by
 464      *          deserialization.
 465      * @throws  StreamCorruptedException Control information in the
 466      *          stream is inconsistent.
 467      * @throws  OptionalDataException Primitive data was found in the
 468      *          stream instead of objects.
 469      * @throws  IOException Any of the usual Input/Output related exceptions.
 470      */
 471     public final Object readObject()
 472         throws IOException, ClassNotFoundException {
 473         return readObject(Object.class);
 474     }
 475 
 476     /**
 477      * Reads a String and only a string.
 478      *
 479      * @return  the String read
 480      * @throws  EOFException If end of file is reached.
 481      * @throws  IOException If other I/O error has occurred.
 482      */
 483     private String readString() throws IOException {
 484         try {
 485             return (String) readObject(String.class);
 486         } catch (ClassNotFoundException cnf) {
 487             throw new IllegalStateException(cnf);
 488         }
 489     }
 490 
 491     /**
 492      * Internal method to read an object from the ObjectInputStream of the expected type.
 493      * Called only from {@code readObject()} and {@code readString()}.
 494      * Only {@code Object.class} and {@code String.class} are supported.
 495      *
 496      * @param type the type expected; either Object.class or String.class
 497      * @return an object of the type
 498      * @throws  IOException Any of the usual Input/Output related exceptions.
 499      * @throws  ClassNotFoundException Class of a serialized object cannot be
 500      *          found.
 501      */
 502     private final Object readObject(Class<?> type)
 503         throws IOException, ClassNotFoundException
 504     {
 505         if (enableOverride) {
 506             return readObjectOverride();
 507         }
 508 
 509         if (! (type == Object.class || type == String.class))
 510             throw new AssertionError("internal error");
 511 
 512         // if nested read, passHandle contains handle of enclosing object
 513         int outerHandle = passHandle;
 514         try {
 515             Object obj = readObject0(type, false);
 516             handles.markDependency(outerHandle, passHandle);
 517             ClassNotFoundException ex = handles.lookupException(passHandle);
 518             if (ex != null) {
 519                 throw ex;
 520             }
 521             if (depth == 0) {
 522                 vlist.doCallbacks();
 523                 freeze();
 524             }
 525             return obj;
 526         } finally {
 527             passHandle = outerHandle;
 528             if (closed && depth == 0) {
 529                 clear();
 530             }
 531         }
 532     }
 533 
 534     /**
 535      * This method is called by trusted subclasses of ObjectInputStream that
 536      * constructed ObjectInputStream using the protected no-arg constructor.
 537      * The subclass is expected to provide an override method with the modifier
 538      * "final".
 539      *
 540      * @return  the Object read from the stream.
 541      * @throws  ClassNotFoundException Class definition of a serialized object
 542      *          cannot be found.
 543      * @throws  OptionalDataException Primitive data was found in the stream
 544      *          instead of objects.
 545      * @throws  IOException if I/O errors occurred while reading from the
 546      *          underlying stream
 547      * @see #ObjectInputStream()
 548      * @see #readObject()
 549      * @since 1.2
 550      */
 551     protected Object readObjectOverride()
 552         throws IOException, ClassNotFoundException
 553     {
 554         return null;
 555     }
 556 
 557     /**
 558      * Reads an "unshared" object from the ObjectInputStream.  This method is
 559      * identical to readObject, except that it prevents subsequent calls to
 560      * readObject and readUnshared from returning additional references to the
 561      * deserialized instance obtained via this call.  Specifically:
 562      * <ul>
 563      *   <li>If readUnshared is called to deserialize a back-reference (the
 564      *       stream representation of an object which has been written
 565      *       previously to the stream), an ObjectStreamException will be
 566      *       thrown.
 567      *
 568      *   <li>If readUnshared returns successfully, then any subsequent attempts
 569      *       to deserialize back-references to the stream handle deserialized
 570      *       by readUnshared will cause an ObjectStreamException to be thrown.
 571      * </ul>
 572      * Deserializing an object via readUnshared invalidates the stream handle
 573      * associated with the returned object.  Note that this in itself does not
 574      * always guarantee that the reference returned by readUnshared is unique;
 575      * the deserialized object may define a readResolve method which returns an
 576      * object visible to other parties, or readUnshared may return a Class
 577      * object or enum constant obtainable elsewhere in the stream or through
 578      * external means. If the deserialized object defines a readResolve method
 579      * and the invocation of that method returns an array, then readUnshared
 580      * returns a shallow clone of that array; this guarantees that the returned
 581      * array object is unique and cannot be obtained a second time from an
 582      * invocation of readObject or readUnshared on the ObjectInputStream,
 583      * even if the underlying data stream has been manipulated.
 584      *
 585      * <p>The deserialization filter, when not {@code null}, is invoked for
 586      * each object (regular or class) read to reconstruct the root object.
 587      * See {@link #setObjectInputFilter(ObjectInputFilter) setObjectInputFilter} for details.
 588      *
 589      * @return  reference to deserialized object
 590      * @throws  ClassNotFoundException if class of an object to deserialize
 591      *          cannot be found
 592      * @throws  StreamCorruptedException if control information in the stream
 593      *          is inconsistent
 594      * @throws  ObjectStreamException if object to deserialize has already
 595      *          appeared in stream
 596      * @throws  OptionalDataException if primitive data is next in stream
 597      * @throws  IOException if an I/O error occurs during deserialization
 598      * @since   1.4
 599      */
 600     public Object readUnshared() throws IOException, ClassNotFoundException {
 601         // if nested read, passHandle contains handle of enclosing object
 602         int outerHandle = passHandle;
 603         try {
 604             Object obj = readObject0(Object.class, true);
 605             handles.markDependency(outerHandle, passHandle);
 606             ClassNotFoundException ex = handles.lookupException(passHandle);
 607             if (ex != null) {
 608                 throw ex;
 609             }
 610             if (depth == 0) {
 611                 vlist.doCallbacks();
 612                 freeze();
 613             }
 614             return obj;
 615         } finally {
 616             passHandle = outerHandle;
 617             if (closed && depth == 0) {
 618                 clear();
 619             }
 620         }
 621     }
 622 
 623     /**
 624      * Read the non-static and non-transient fields of the current class from
 625      * this stream.  This may only be called from the readObject method of the
 626      * class being deserialized. It will throw the NotActiveException if it is
 627      * called otherwise.
 628      *
 629      * @throws  ClassNotFoundException if the class of a serialized object
 630      *          could not be found.
 631      * @throws  IOException if an I/O error occurs.
 632      * @throws  NotActiveException if the stream is not currently reading
 633      *          objects.
 634      */
 635     public void defaultReadObject()
 636         throws IOException, ClassNotFoundException
 637     {
 638         SerialCallbackContext ctx = curContext;
 639         if (ctx == null) {
 640             throw new NotActiveException("not in call to readObject");
 641         }
 642         Object curObj = ctx.getObj();
 643         ObjectStreamClass curDesc = ctx.getDesc();
 644         bin.setBlockDataMode(false);
 645 
 646         // Read fields of the current descriptor into a new FieldValues
 647         FieldValues values = new FieldValues(curDesc, true);
 648         if (curObj != null) {
 649             values.defaultCheckFieldValues(curObj);
 650             values.defaultSetFieldValues(curObj);
 651         }
 652         bin.setBlockDataMode(true);
 653         if (!curDesc.hasWriteObjectData()) {
 654             /*
 655              * Fix for 4360508: since stream does not contain terminating
 656              * TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere
 657              * knows to simulate end-of-custom-data behavior.
 658              */
 659             defaultDataEnd = true;
 660         }
 661         ClassNotFoundException ex = handles.lookupException(passHandle);
 662         if (ex != null) {
 663             throw ex;
 664         }
 665     }
 666 
 667     /**
 668      * Reads the persistent fields from the stream and makes them available by
 669      * name.
 670      *
 671      * @return  the {@code GetField} object representing the persistent
 672      *          fields of the object being deserialized
 673      * @throws  ClassNotFoundException if the class of a serialized object
 674      *          could not be found.
 675      * @throws  IOException if an I/O error occurs.
 676      * @throws  NotActiveException if the stream is not currently reading
 677      *          objects.
 678      * @since 1.2
 679      */
 680     public ObjectInputStream.GetField readFields()
 681         throws IOException, ClassNotFoundException
 682     {
 683         SerialCallbackContext ctx = curContext;
 684         if (ctx == null) {
 685             throw new NotActiveException("not in call to readObject");
 686         }
 687         ctx.checkAndSetUsed();
 688         ObjectStreamClass curDesc = ctx.getDesc();
 689         bin.setBlockDataMode(false);
 690         // Read fields of the current descriptor into a new FieldValues
 691         FieldValues values = new FieldValues(curDesc, false);
 692         bin.setBlockDataMode(true);
 693         if (!curDesc.hasWriteObjectData()) {
 694             /*
 695              * Fix for 4360508: since stream does not contain terminating
 696              * TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere
 697              * knows to simulate end-of-custom-data behavior.
 698              */
 699             defaultDataEnd = true;
 700         }
 701         return values;
 702     }
 703 
 704     /**
 705      * Register an object to be validated before the graph is returned.  While
 706      * similar to resolveObject these validations are called after the entire
 707      * graph has been reconstituted.  Typically, a readObject method will
 708      * register the object with the stream so that when all of the objects are
 709      * restored a final set of validations can be performed.
 710      *
 711      * @param   obj the object to receive the validation callback.
 712      * @param   prio controls the order of callbacks; zero is a good default.
 713      *          Use higher numbers to be called back earlier, lower numbers for
 714      *          later callbacks. Within a priority, callbacks are processed in
 715      *          no particular order.
 716      * @throws  NotActiveException The stream is not currently reading objects
 717      *          so it is invalid to register a callback.
 718      * @throws  InvalidObjectException The validation object is null.
 719      */
 720     public void registerValidation(ObjectInputValidation obj, int prio)
 721         throws NotActiveException, InvalidObjectException
 722     {
 723         if (depth == 0) {
 724             throw new NotActiveException("stream inactive");
 725         }
 726         vlist.register(obj, prio);
 727     }
 728 
 729     /**
 730      * Load the local class equivalent of the specified stream class
 731      * description.  Subclasses may implement this method to allow classes to
 732      * be fetched from an alternate source.
 733      *
 734      * <p>The corresponding method in {@code ObjectOutputStream} is
 735      * {@code annotateClass}.  This method will be invoked only once for
 736      * each unique class in the stream.  This method can be implemented by
 737      * subclasses to use an alternate loading mechanism but must return a
 738      * {@code Class} object. Once returned, if the class is not an array
 739      * class, its serialVersionUID is compared to the serialVersionUID of the
 740      * serialized class, and if there is a mismatch, the deserialization fails
 741      * and an {@link InvalidClassException} is thrown.
 742      *
 743      * <p>The default implementation of this method in
 744      * {@code ObjectInputStream} returns the result of calling
 745      * {@snippet lang="java":
 746      *     Class.forName(desc.getName(), false, loader)
 747      * }
 748      * where {@code loader} is the first class loader on the current
 749      * thread's stack (starting from the currently executing method) that is
 750      * neither the {@linkplain ClassLoader#getPlatformClassLoader() platform
 751      * class loader} nor its ancestor; otherwise, {@code loader} is the
 752      * <em>platform class loader</em>. If this call results in a
 753      * {@code ClassNotFoundException} and the name of the passed
 754      * {@code ObjectStreamClass} instance is the Java language keyword
 755      * for a primitive type or void, then the {@code Class} object
 756      * representing that primitive type or void will be returned
 757      * (e.g., an {@code ObjectStreamClass} with the name
 758      * {@code "int"} will be resolved to {@code Integer.TYPE}).
 759      * Otherwise, the {@code ClassNotFoundException} will be thrown to
 760      * the caller of this method.
 761      *
 762      * @param   desc an instance of class {@code ObjectStreamClass}
 763      * @return  a {@code Class} object corresponding to {@code desc}
 764      * @throws  IOException any of the usual Input/Output exceptions.
 765      * @throws  ClassNotFoundException if class of a serialized object cannot
 766      *          be found.
 767      */
 768     protected Class<?> resolveClass(ObjectStreamClass desc)
 769         throws IOException, ClassNotFoundException
 770     {
 771         String name = desc.getName();
 772         try {
 773             return Class.forName(name, false, latestUserDefinedLoader());
 774         } catch (ClassNotFoundException ex) {
 775             Class<?> cl = Class.forPrimitiveName(name);
 776             if (cl != null) {
 777                 return cl;
 778             } else {
 779                 throw ex;
 780             }
 781         }
 782     }
 783 
 784     /**
 785      * Returns a proxy class that implements the interfaces named in a proxy
 786      * class descriptor; subclasses may implement this method to read custom
 787      * data from the stream along with the descriptors for dynamic proxy
 788      * classes, allowing them to use an alternate loading mechanism for the
 789      * interfaces and the proxy class.
 790      *
 791      * <p>This method is called exactly once for each unique proxy class
 792      * descriptor in the stream.
 793      *
 794      * <p>The corresponding method in {@code ObjectOutputStream} is
 795      * {@code annotateProxyClass}.  For a given subclass of
 796      * {@code ObjectInputStream} that overrides this method, the
 797      * {@code annotateProxyClass} method in the corresponding subclass of
 798      * {@code ObjectOutputStream} must write any data or objects read by
 799      * this method.
 800      *
 801      * <p>The default implementation of this method in
 802      * {@code ObjectInputStream} returns the result of calling
 803      * {@code Proxy.getProxyClass} with the list of {@code Class}
 804      * objects for the interfaces that are named in the {@code interfaces}
 805      * parameter.  The {@code Class} object for each interface name
 806      * {@code i} is the value returned by calling
 807      * {@snippet lang="java":
 808      *     Class.forName(i, false, loader)
 809      * }
 810      * where {@code loader} is the first class loader on the current
 811      * thread's stack (starting from the currently executing method) that is
 812      * neither the {@linkplain ClassLoader#getPlatformClassLoader() platform
 813      * class loader} nor its ancestor; otherwise, {@code loader} is the
 814      * <em>platform class loader</em>.
 815      * Unless any of the resolved interfaces are non-public, this same value
 816      * of {@code loader} is also the class loader passed to
 817      * {@code Proxy.getProxyClass}; if non-public interfaces are present,
 818      * their class loader is passed instead (if more than one non-public
 819      * interface class loader is encountered, an
 820      * {@code IllegalAccessError} is thrown).
 821      * If {@code Proxy.getProxyClass} throws an
 822      * {@code IllegalArgumentException}, {@code resolveProxyClass}
 823      * will throw a {@code ClassNotFoundException} containing the
 824      * {@code IllegalArgumentException}.
 825      *
 826      * @param interfaces the list of interface names that were
 827      *                deserialized in the proxy class descriptor
 828      * @return  a proxy class for the specified interfaces
 829      * @throws        IOException any exception thrown by the underlying
 830      *                {@code InputStream}
 831      * @throws        ClassNotFoundException if the proxy class or any of the
 832      *                named interfaces could not be found
 833      * @see ObjectOutputStream#annotateProxyClass(Class)
 834      * @since 1.3
 835      */
 836     protected Class<?> resolveProxyClass(String[] interfaces)
 837         throws IOException, ClassNotFoundException
 838     {
 839         ClassLoader latestLoader = latestUserDefinedLoader();
 840         ClassLoader nonPublicLoader = null;
 841         boolean hasNonPublicInterface = false;
 842 
 843         // define proxy in class loader of non-public interface(s), if any
 844         Class<?>[] classObjs = new Class<?>[interfaces.length];
 845         for (int i = 0; i < interfaces.length; i++) {
 846             Class<?> cl = Class.forName(interfaces[i], false, latestLoader);
 847             if ((cl.getModifiers() & Modifier.PUBLIC) == 0) {
 848                 if (hasNonPublicInterface) {
 849                     if (nonPublicLoader != cl.getClassLoader()) {
 850                         throw new IllegalAccessError(
 851                             "conflicting non-public interface class loaders");
 852                     }
 853                 } else {
 854                     nonPublicLoader = cl.getClassLoader();
 855                     hasNonPublicInterface = true;
 856                 }
 857             }
 858             classObjs[i] = cl;
 859         }
 860         try {
 861             @SuppressWarnings("deprecation")
 862             Class<?> proxyClass = Proxy.getProxyClass(
 863                 hasNonPublicInterface ? nonPublicLoader : latestLoader,
 864                 classObjs);
 865             return proxyClass;
 866         } catch (IllegalArgumentException e) {
 867             throw new ClassNotFoundException(null, e);
 868         }
 869     }
 870 
 871     /**
 872      * This method will allow trusted subclasses of ObjectInputStream to
 873      * substitute one object for another during deserialization. Replacing
 874      * objects is disabled until enableResolveObject is called. The
 875      * enableResolveObject method checks that the stream requesting to resolve
 876      * object can be trusted. Every reference to serializable objects is passed
 877      * to resolveObject.  To ensure that the private state of objects is not
 878      * unintentionally exposed only trusted streams may use resolveObject.
 879      *
 880      * <p>This method is called after an object has been read but before it is
 881      * returned from readObject.  The default resolveObject method just returns
 882      * the same object.
 883      *
 884      * <p>When a subclass is replacing objects it must ensure that the
 885      * substituted object is compatible with every field where the reference
 886      * will be stored.  Objects whose type is not a subclass of the type of the
 887      * field or array element abort the deserialization by raising an exception
 888      * and the object is not be stored.
 889      *
 890      * <p>This method is called only once when each object is first
 891      * encountered.  All subsequent references to the object will be redirected
 892      * to the new object.
 893      *
 894      * @param   obj object to be substituted
 895      * @return  the substituted object
 896      * @throws  IOException Any of the usual Input/Output exceptions.
 897      */
 898     protected Object resolveObject(Object obj) throws IOException {
 899         return obj;
 900     }
 901 
 902     /**
 903      * Enables the stream to do replacement of objects read from the stream. When
 904      * enabled, the {@link #resolveObject} method is called for every object being
 905      * deserialized.
 906      *
 907      * @param   enable true for enabling use of {@code resolveObject} for
 908      *          every object being deserialized
 909      * @return  the previous setting before this method was invoked
 910      */
 911     protected boolean enableResolveObject(boolean enable) {
 912         if (enable == enableResolve) {
 913             return enable;
 914         }
 915         enableResolve = enable;
 916         return !enableResolve;
 917     }
 918 
 919     /**
 920      * The readStreamHeader method is provided to allow subclasses to read and
 921      * verify their own stream headers. It reads and verifies the magic number
 922      * and version number.
 923      *
 924      * @throws  IOException if there are I/O errors while reading from the
 925      *          underlying {@code InputStream}
 926      * @throws  StreamCorruptedException if control information in the stream
 927      *          is inconsistent
 928      */
 929     protected void readStreamHeader()
 930         throws IOException, StreamCorruptedException
 931     {
 932         short s0 = bin.readShort();
 933         short s1 = bin.readShort();
 934         if (s0 != STREAM_MAGIC || s1 != STREAM_VERSION) {
 935             throw new StreamCorruptedException(
 936                 String.format("invalid stream header: %04X%04X", s0, s1));
 937         }
 938     }
 939 
 940     /**
 941      * Read a class descriptor from the serialization stream.  This method is
 942      * called when the ObjectInputStream expects a class descriptor as the next
 943      * item in the serialization stream.  Subclasses of ObjectInputStream may
 944      * override this method to read in class descriptors that have been written
 945      * in non-standard formats (by subclasses of ObjectOutputStream which have
 946      * overridden the {@code writeClassDescriptor} method).  By default,
 947      * this method reads class descriptors according to the format defined in
 948      * the Object Serialization specification.
 949      *
 950      * @return  the class descriptor read
 951      * @throws  IOException If an I/O error has occurred.
 952      * @throws  ClassNotFoundException If the Class of a serialized object used
 953      *          in the class descriptor representation cannot be found
 954      * @see java.io.ObjectOutputStream#writeClassDescriptor(java.io.ObjectStreamClass)
 955      * @since 1.3
 956      */
 957     protected ObjectStreamClass readClassDescriptor()
 958         throws IOException, ClassNotFoundException
 959     {
 960         ObjectStreamClass desc = new ObjectStreamClass();
 961         desc.readNonProxy(this);
 962         return desc;
 963     }
 964 
 965     /**
 966      * Reads a byte of data. This method will block if no input is available.
 967      *
 968      * @return  the byte read, or -1 if the end of the stream is reached.
 969      * @throws  IOException {@inheritDoc}
 970      */
 971     @Override
 972     public int read() throws IOException {
 973         return bin.read();
 974     }
 975 
 976     /**
 977      * Reads into an array of bytes.  This method will block until some input
 978      * is available. Consider using java.io.DataInputStream.readFully to read
 979      * exactly 'length' bytes.
 980      *
 981      * @param   buf the buffer into which the data is read
 982      * @param   off the start offset in the destination array {@code buf}
 983      * @param   len the maximum number of bytes read
 984      * @return  the total number of bytes read into the buffer, or
 985      *          {@code -1} if there is no more data because the end of
 986      *          the stream has been reached.
 987      * @throws  NullPointerException if {@code buf} is {@code null}.
 988      * @throws  IndexOutOfBoundsException if {@code off} is negative,
 989      *          {@code len} is negative, or {@code len} is greater than
 990      *          {@code buf.length - off}.
 991      * @throws  IOException If an I/O error has occurred.
 992      * @see java.io.DataInputStream#readFully(byte[],int,int)
 993      */
 994     @Override
 995     public int read(byte[] buf, int off, int len) throws IOException {
 996         if (buf == null) {
 997             throw new NullPointerException();
 998         }
 999         Objects.checkFromIndexSize(off, len, buf.length);
1000         return bin.read(buf, off, len, false);
1001     }
1002 
1003     /**
1004      * Returns the number of bytes that can be read without blocking.
1005      *
1006      * @return  the number of available bytes.
1007      * @throws  IOException if there are I/O errors while reading from the
1008      *          underlying {@code InputStream}
1009      */
1010     @Override
1011     public int available() throws IOException {
1012         return bin.available();
1013     }
1014 
1015     /**
1016      * {@inheritDoc}
1017      *
1018      * @throws  IOException {@inheritDoc}
1019      */
1020     @Override
1021     public void close() throws IOException {
1022         /*
1023          * Even if stream already closed, propagate redundant close to
1024          * underlying stream to stay consistent with previous implementations.
1025          */
1026         closed = true;
1027         if (depth == 0) {
1028             clear();
1029         }
1030         bin.close();
1031     }
1032 
1033     /**
1034      * Reads in a boolean.
1035      *
1036      * @return  the boolean read.
1037      * @throws  EOFException If end of file is reached.
1038      * @throws  IOException If other I/O error has occurred.
1039      */
1040     public boolean readBoolean() throws IOException {
1041         return bin.readBoolean();
1042     }
1043 
1044     /**
1045      * Reads an 8-bit byte.
1046      *
1047      * @return  the 8-bit byte read.
1048      * @throws  EOFException If end of file is reached.
1049      * @throws  IOException If other I/O error has occurred.
1050      */
1051     public byte readByte() throws IOException  {
1052         return bin.readByte();
1053     }
1054 
1055     /**
1056      * Reads an unsigned 8-bit byte.
1057      *
1058      * @return  the 8-bit byte read.
1059      * @throws  EOFException If end of file is reached.
1060      * @throws  IOException If other I/O error has occurred.
1061      */
1062     public int readUnsignedByte()  throws IOException {
1063         return bin.readUnsignedByte();
1064     }
1065 
1066     /**
1067      * Reads a 16-bit char.
1068      *
1069      * @return  the 16-bit char read.
1070      * @throws  EOFException If end of file is reached.
1071      * @throws  IOException If other I/O error has occurred.
1072      */
1073     public char readChar()  throws IOException {
1074         return bin.readChar();
1075     }
1076 
1077     /**
1078      * Reads a 16-bit short.
1079      *
1080      * @return  the 16-bit short read.
1081      * @throws  EOFException If end of file is reached.
1082      * @throws  IOException If other I/O error has occurred.
1083      */
1084     public short readShort()  throws IOException {
1085         return bin.readShort();
1086     }
1087 
1088     /**
1089      * Reads an unsigned 16-bit short.
1090      *
1091      * @return  the 16-bit short read.
1092      * @throws  EOFException If end of file is reached.
1093      * @throws  IOException If other I/O error has occurred.
1094      */
1095     public int readUnsignedShort() throws IOException {
1096         return bin.readUnsignedShort();
1097     }
1098 
1099     /**
1100      * Reads a 32-bit int.
1101      *
1102      * @return  the 32-bit integer read.
1103      * @throws  EOFException If end of file is reached.
1104      * @throws  IOException If other I/O error has occurred.
1105      */
1106     public int readInt()  throws IOException {
1107         return bin.readInt();
1108     }
1109 
1110     /**
1111      * Reads a 64-bit long.
1112      *
1113      * @return  the read 64-bit long.
1114      * @throws  EOFException If end of file is reached.
1115      * @throws  IOException If other I/O error has occurred.
1116      */
1117     public long readLong()  throws IOException {
1118         return bin.readLong();
1119     }
1120 
1121     /**
1122      * Reads a 32-bit float.
1123      *
1124      * @return  the 32-bit float read.
1125      * @throws  EOFException If end of file is reached.
1126      * @throws  IOException If other I/O error has occurred.
1127      */
1128     public float readFloat() throws IOException {
1129         return bin.readFloat();
1130     }
1131 
1132     /**
1133      * Reads a 64-bit double.
1134      *
1135      * @return  the 64-bit double read.
1136      * @throws  EOFException If end of file is reached.
1137      * @throws  IOException If other I/O error has occurred.
1138      */
1139     public double readDouble() throws IOException {
1140         return bin.readDouble();
1141     }
1142 
1143     /**
1144      * Reads bytes, blocking until all bytes are read.
1145      *
1146      * @param   buf the buffer into which the data is read
1147      * @throws  NullPointerException If {@code buf} is {@code null}.
1148      * @throws  EOFException If end of file is reached.
1149      * @throws  IOException If other I/O error has occurred.
1150      */
1151     public void readFully(byte[] buf) throws IOException {
1152         bin.readFully(buf, 0, buf.length, false);
1153     }
1154 
1155     /**
1156      * Reads bytes, blocking until all bytes are read.
1157      *
1158      * @param   buf the buffer into which the data is read
1159      * @param   off the start offset into the data array {@code buf}
1160      * @param   len the maximum number of bytes to read
1161      * @throws  NullPointerException If {@code buf} is {@code null}.
1162      * @throws  IndexOutOfBoundsException If {@code off} is negative,
1163      *          {@code len} is negative, or {@code len} is greater than
1164      *          {@code buf.length - off}.
1165      * @throws  EOFException If end of file is reached.
1166      * @throws  IOException If other I/O error has occurred.
1167      */
1168     public void readFully(byte[] buf, int off, int len) throws IOException {
1169         Objects.checkFromIndexSize(off, len, buf.length);
1170         bin.readFully(buf, off, len, false);
1171     }
1172 
1173     /**
1174      * Skips bytes.
1175      *
1176      * @param   len the number of bytes to be skipped
1177      * @return  the actual number of bytes skipped.
1178      * @throws  IOException If an I/O error has occurred.
1179      */
1180     @Override
1181     public int skipBytes(int len) throws IOException {
1182         return bin.skipBytes(len);
1183     }
1184 
1185     /**
1186      * Reads in a line that has been terminated by a \n, \r, \r\n or EOF.
1187      *
1188      * @return  a String copy of the line.
1189      * @throws  IOException if there are I/O errors while reading from the
1190      *          underlying {@code InputStream}
1191      * @deprecated This method does not properly convert bytes to characters.
1192      *          see DataInputStream for the details and alternatives.
1193      */
1194     @Deprecated
1195     public String readLine() throws IOException {
1196         return bin.readLine();
1197     }
1198 
1199     /**
1200      * Reads a String in
1201      * <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
1202      * format.
1203      *
1204      * @return  the String.
1205      * @throws  IOException if there are I/O errors while reading from the
1206      *          underlying {@code InputStream}
1207      * @throws  UTFDataFormatException if read bytes do not represent a valid
1208      *          modified UTF-8 encoding of a string
1209      */
1210     public String readUTF() throws IOException {
1211         return bin.readUTF();
1212     }
1213 
1214     /**
1215      * Returns the deserialization filter for this stream.
1216      * The filter is the result of invoking the
1217      * {@link Config#getSerialFilterFactory() JVM-wide filter factory}
1218      * either by the {@linkplain #ObjectInputStream() constructor} or the most recent invocation of
1219      * {@link #setObjectInputFilter setObjectInputFilter}.
1220      *
1221      * @return the deserialization filter for the stream; may be null
1222      * @since 9
1223      */
1224     public final ObjectInputFilter getObjectInputFilter() {
1225         return serialFilter;
1226     }
1227 
1228     /**
1229      * Set the deserialization filter for the stream.
1230      *
1231      * The deserialization filter is set to the filter returned by invoking the
1232      * {@linkplain Config#getSerialFilterFactory() JVM-wide filter factory}
1233      * with the {@linkplain #getObjectInputFilter() current filter} and the {@code filter} parameter.
1234      * The current filter was set in the
1235      * {@linkplain #ObjectInputStream() ObjectInputStream constructors} by invoking the
1236      * {@linkplain Config#getSerialFilterFactory() JVM-wide filter factory} and may be {@code null}.
1237      * {@linkplain #setObjectInputFilter(ObjectInputFilter)} This method} can be called
1238      * once and only once before reading any objects from the stream;
1239      * for example, by calling {@link #readObject} or {@link #readUnshared}.
1240      *
1241      * <p>It is not permitted to replace a {@code non-null} filter with a {@code null} filter.
1242      * If the {@linkplain #getObjectInputFilter() current filter} is {@code non-null},
1243      * the value returned from the filter factory must be {@code non-null}.
1244      *
1245      * <p>The filter's {@link ObjectInputFilter#checkInput checkInput} method is called
1246      * for each class and reference in the stream.
1247      * The filter can check any or all of the class, the array length, the number
1248      * of references, the depth of the graph, and the size of the input stream.
1249      * The depth is the number of nested {@linkplain #readObject readObject}
1250      * calls starting with the reading of the root of the graph being deserialized
1251      * and the current object being deserialized.
1252      * The number of references is the cumulative number of objects and references
1253      * to objects already read from the stream including the current object being read.
1254      * The filter is invoked only when reading objects from the stream and not for
1255      * primitives.
1256      * <p>
1257      * If the filter returns {@link ObjectInputFilter.Status#REJECTED Status.REJECTED},
1258      * {@code null} or throws a {@link RuntimeException},
1259      * the active {@code readObject} or {@code readUnshared}
1260      * throws {@link InvalidClassException}, otherwise deserialization
1261      * continues uninterrupted.
1262      *
1263      * @implSpec
1264      * The filter, when not {@code null}, is invoked during {@link #readObject readObject}
1265      * and {@link #readUnshared readUnshared} for each object (regular or class) in the stream.
1266      * Strings are treated as primitives and do not invoke the filter.
1267      * The filter is called for:
1268      * <ul>
1269      *     <li>each object reference previously deserialized from the stream
1270      *     (class is {@code null}, arrayLength is -1),
1271      *     <li>each regular class (class is not {@code null}, arrayLength is -1),
1272      *     <li>each interface class explicitly referenced in the stream
1273      *         (it is not called for interfaces implemented by classes in the stream),
1274      *     <li>each interface of a dynamic proxy and the dynamic proxy class itself
1275      *     (class is not {@code null}, arrayLength is -1),
1276      *     <li>each array is filtered using the array type and length of the array
1277      *     (class is the array type, arrayLength is the requested length),
1278      *     <li>each object replaced by its class' {@code readResolve} method
1279      *         is filtered using the replacement object's class, if not {@code null},
1280      *         and if it is an array, the arrayLength, otherwise -1,
1281      *     <li>and each object replaced by {@link #resolveObject resolveObject}
1282      *         is filtered using the replacement object's class, if not {@code null},
1283      *         and if it is an array, the arrayLength, otherwise -1.
1284      * </ul>
1285      *
1286      * When the {@link ObjectInputFilter#checkInput checkInput} method is invoked
1287      * it is given access to the current class, the array length,
1288      * the current number of references already read from the stream,
1289      * the depth of nested calls to {@link #readObject readObject} or
1290      * {@link #readUnshared readUnshared},
1291      * and the implementation dependent number of bytes consumed from the input stream.
1292      * <p>
1293      * Each call to {@link #readObject readObject} or
1294      * {@link #readUnshared readUnshared} increases the depth by 1
1295      * before reading an object and decreases by 1 before returning
1296      * normally or exceptionally.
1297      * The depth starts at {@code 1} and increases for each nested object and
1298      * decrements when each nested call returns.
1299      * The count of references in the stream starts at {@code 1} and
1300      * is increased before reading an object.
1301      *
1302      * @param filter the filter, may be null
1303      * @throws IllegalStateException if an object has been read,
1304      *       if the filter factory returns {@code null} when the
1305      *       {@linkplain #getObjectInputFilter() current filter} is non-null, or
1306      *       if the filter has already been set.
1307      * @since 9
1308      */
1309     public final void setObjectInputFilter(ObjectInputFilter filter) {
1310         if (totalObjectRefs > 0 && !Caches.SET_FILTER_AFTER_READ) {
1311             throw new IllegalStateException(
1312                     "filter can not be set after an object has been read");
1313         }
1314         if (streamFilterSet) {
1315             throw new IllegalStateException("filter can not be set more than once");
1316         }
1317         streamFilterSet = true;
1318         // Delegate to serialFilterFactory to compute stream filter
1319         ObjectInputFilter next = Config.getSerialFilterFactory()
1320                 .apply(serialFilter, filter);
1321         if (serialFilter != null && next == null) {
1322             throw new IllegalStateException("filter can not be replaced with null filter");
1323         }
1324         serialFilter = next;
1325     }
1326 
1327     /**
1328      * Invokes the deserialization filter if non-null.
1329      *
1330      * If the filter rejects or an exception is thrown, throws InvalidClassException.
1331      *
1332      * Logs and/or commits a {@code DeserializationEvent}, if configured.
1333      *
1334      * @param clazz the class; may be null
1335      * @param arrayLength the array length requested; use {@code -1} if not creating an array
1336      * @throws InvalidClassException if it rejected by the filter or
1337      *        a {@link RuntimeException} is thrown
1338      */
1339     private void filterCheck(Class<?> clazz, int arrayLength)
1340             throws InvalidClassException {
1341         // Info about the stream is not available if overridden by subclass, return 0
1342         long bytesRead = (bin == null) ? 0 : bin.getBytesRead();
1343         RuntimeException ex = null;
1344         ObjectInputFilter.Status status = null;
1345 
1346         if (serialFilter != null) {
1347             try {
1348                 status = serialFilter.checkInput(new FilterValues(clazz, arrayLength,
1349                         totalObjectRefs, depth, bytesRead));
1350             } catch (RuntimeException e) {
1351                 // Preventive interception of an exception to log
1352                 status = ObjectInputFilter.Status.REJECTED;
1353                 ex = e;
1354             }
1355             if (Logging.filterLogger != null) {
1356                 // Debug logging of filter checks that fail; Tracing for those that succeed
1357                 Logging.filterLogger.log(status == null || status == ObjectInputFilter.Status.REJECTED
1358                                 ? Logger.Level.DEBUG
1359                                 : Logger.Level.TRACE,
1360                         "ObjectInputFilter {0}: {1}, array length: {2}, nRefs: {3}, depth: {4}, bytes: {5}, ex: {6}",
1361                         status, clazz, arrayLength, totalObjectRefs, depth, bytesRead,
1362                         Objects.toString(ex, "n/a"));
1363             }
1364         }
1365         DeserializationEvent event = new DeserializationEvent();
1366         if (event.shouldCommit()) {
1367             event.filterConfigured = serialFilter != null;
1368             event.filterStatus = status != null ? status.name() : null;
1369             event.type = clazz;
1370             event.arrayLength = arrayLength;
1371             event.objectReferences = totalObjectRefs;
1372             event.depth = depth;
1373             event.bytesRead = bytesRead;
1374             event.exceptionType = ex != null ? ex.getClass() : null;
1375             event.exceptionMessage = ex != null ? ex.getMessage() : null;
1376             event.commit();
1377         }
1378         if (serialFilter != null && (status == null || status == ObjectInputFilter.Status.REJECTED)) {
1379             throw new InvalidClassException("filter status: " + status, ex);
1380         }
1381     }
1382 
1383     /**
1384      * Checks the given array type and length to ensure that creation of such
1385      * an array is permitted by this ObjectInputStream. The arrayType argument
1386      * must represent an actual array type.
1387      *
1388      * This private method is called via SharedSecrets.
1389      *
1390      * @param arrayType the array type
1391      * @param arrayLength the array length
1392      * @throws NullPointerException if arrayType is null
1393      * @throws IllegalArgumentException if arrayType isn't actually an array type
1394      * @throws StreamCorruptedException if arrayLength is negative
1395      * @throws InvalidClassException if the filter rejects creation
1396      */
1397     private void checkArray(Class<?> arrayType, int arrayLength) throws ObjectStreamException {
1398         if (! arrayType.isArray()) {
1399             throw new IllegalArgumentException("not an array type");
1400         }
1401 
1402         if (arrayLength < 0) {
1403             throw new StreamCorruptedException("Array length is negative");
1404         }
1405 
1406         filterCheck(arrayType, arrayLength);
1407     }
1408 
1409     /**
1410      * Provide access to the persistent fields read from the input stream.
1411      */
1412     public abstract static class GetField {
1413         /**
1414          * Constructor for subclasses to call.
1415          */
1416         public GetField() {}
1417 
1418         /**
1419          * Get the ObjectStreamClass that describes the fields in the stream.
1420          *
1421          * @return  the descriptor class that describes the serializable fields
1422          */
1423         public abstract ObjectStreamClass getObjectStreamClass();
1424 
1425         /**
1426          * Return true if the named field is defaulted and has no value in this
1427          * stream.
1428          *
1429          * @param  name the name of the field
1430          * @return true, if and only if the named field is defaulted
1431          * @throws IOException if there are I/O errors while reading from
1432          *         the underlying {@code InputStream}
1433          * @throws IllegalArgumentException if {@code name} does not
1434          *         correspond to a serializable field
1435          */
1436         public abstract boolean defaulted(String name) throws IOException;
1437 
1438         /**
1439          * Get the value of the named boolean field from the persistent field.
1440          *
1441          * @param  name the name of the field
1442          * @param  val the default value to use if {@code name} does not
1443          *         have a value
1444          * @return the value of the named {@code boolean} field
1445          * @throws IOException if there are I/O errors while reading from the
1446          *         underlying {@code InputStream}
1447          * @throws IllegalArgumentException if type of {@code name} is
1448          *         not serializable or if the field type is incorrect
1449          */
1450         public abstract boolean get(String name, boolean val)
1451             throws IOException;
1452 
1453         /**
1454          * Get the value of the named byte field from the persistent field.
1455          *
1456          * @param  name the name of the field
1457          * @param  val the default value to use if {@code name} does not
1458          *         have a value
1459          * @return the value of the named {@code byte} field
1460          * @throws IOException if there are I/O errors while reading from the
1461          *         underlying {@code InputStream}
1462          * @throws IllegalArgumentException if type of {@code name} is
1463          *         not serializable or if the field type is incorrect
1464          */
1465         public abstract byte get(String name, byte val) throws IOException;
1466 
1467         /**
1468          * Get the value of the named char field from the persistent field.
1469          *
1470          * @param  name the name of the field
1471          * @param  val the default value to use if {@code name} does not
1472          *         have a value
1473          * @return the value of the named {@code char} field
1474          * @throws IOException if there are I/O errors while reading from the
1475          *         underlying {@code InputStream}
1476          * @throws IllegalArgumentException if type of {@code name} is
1477          *         not serializable or if the field type is incorrect
1478          */
1479         public abstract char get(String name, char val) throws IOException;
1480 
1481         /**
1482          * Get the value of the named short field from the persistent field.
1483          *
1484          * @param  name the name of the field
1485          * @param  val the default value to use if {@code name} does not
1486          *         have a value
1487          * @return the value of the named {@code short} field
1488          * @throws IOException if there are I/O errors while reading from the
1489          *         underlying {@code InputStream}
1490          * @throws IllegalArgumentException if type of {@code name} is
1491          *         not serializable or if the field type is incorrect
1492          */
1493         public abstract short get(String name, short val) throws IOException;
1494 
1495         /**
1496          * Get the value of the named int field from the persistent field.
1497          *
1498          * @param  name the name of the field
1499          * @param  val the default value to use if {@code name} does not
1500          *         have a value
1501          * @return the value of the named {@code int} field
1502          * @throws IOException if there are I/O errors while reading from the
1503          *         underlying {@code InputStream}
1504          * @throws IllegalArgumentException if type of {@code name} is
1505          *         not serializable or if the field type is incorrect
1506          */
1507         public abstract int get(String name, int val) throws IOException;
1508 
1509         /**
1510          * Get the value of the named long field from the persistent field.
1511          *
1512          * @param  name the name of the field
1513          * @param  val the default value to use if {@code name} does not
1514          *         have a value
1515          * @return the value of the named {@code long} field
1516          * @throws IOException if there are I/O errors while reading from the
1517          *         underlying {@code InputStream}
1518          * @throws IllegalArgumentException if type of {@code name} is
1519          *         not serializable or if the field type is incorrect
1520          */
1521         public abstract long get(String name, long val) throws IOException;
1522 
1523         /**
1524          * Get the value of the named float field from the persistent field.
1525          *
1526          * @param  name the name of the field
1527          * @param  val the default value to use if {@code name} does not
1528          *         have a value
1529          * @return the value of the named {@code float} field
1530          * @throws IOException if there are I/O errors while reading from the
1531          *         underlying {@code InputStream}
1532          * @throws IllegalArgumentException if type of {@code name} is
1533          *         not serializable or if the field type is incorrect
1534          */
1535         public abstract float get(String name, float val) throws IOException;
1536 
1537         /**
1538          * Get the value of the named double field from the persistent field.
1539          *
1540          * @param  name the name of the field
1541          * @param  val the default value to use if {@code name} does not
1542          *         have a value
1543          * @return the value of the named {@code double} field
1544          * @throws IOException if there are I/O errors while reading from the
1545          *         underlying {@code InputStream}
1546          * @throws IllegalArgumentException if type of {@code name} is
1547          *         not serializable or if the field type is incorrect
1548          */
1549         public abstract double get(String name, double val) throws IOException;
1550 
1551         /**
1552          * Get the value of the named Object field from the persistent field.
1553          *
1554          * @param  name the name of the field
1555          * @param  val the default value to use if {@code name} does not
1556          *         have a value
1557          * @return the value of the named {@code Object} field
1558          * @throws ClassNotFoundException Class of a serialized object cannot be found.
1559          * @throws IOException if there are I/O errors while reading from the
1560          *         underlying {@code InputStream}
1561          * @throws IllegalArgumentException if type of {@code name} is
1562          *         not serializable or if the field type is incorrect
1563          */
1564         public abstract Object get(String name, Object val) throws IOException, ClassNotFoundException;
1565     }
1566 
1567     /**
1568      * Clears internal data structures.
1569      */
1570     private void clear() {
1571         handles.clear();
1572         vlist.clear();
1573     }
1574 
1575     /**
1576      * Underlying readObject implementation.
1577      * @param type a type expected to be deserialized; non-null
1578      * @param unshared true if the object can not be a reference to a shared object, otherwise false
1579      */
1580     private Object readObject0(Class<?> type, boolean unshared) throws IOException {
1581         boolean oldMode = bin.getBlockDataMode();
1582         if (oldMode) {
1583             int remain = bin.currentBlockRemaining();
1584             if (remain > 0) {
1585                 throw new OptionalDataException(remain);
1586             } else if (defaultDataEnd) {
1587                 /*
1588                  * Fix for 4360508: stream is currently at the end of a field
1589                  * value block written via default serialization; since there
1590                  * is no terminating TC_ENDBLOCKDATA tag, simulate
1591                  * end-of-custom-data behavior explicitly.
1592                  */
1593                 throw new OptionalDataException(true);
1594             }
1595             bin.setBlockDataMode(false);
1596         }
1597 
1598         byte tc;
1599         while ((tc = bin.peekByte()) == TC_RESET) {
1600             bin.readByte();
1601             handleReset();
1602         }
1603 
1604         depth++;
1605         totalObjectRefs++;
1606         try {
1607             switch (tc) {
1608                 case TC_NULL:
1609                     return readNull();
1610 
1611                 case TC_REFERENCE:
1612                     // check the type of the existing object
1613                     return type.cast(readHandle(unshared));
1614 
1615                 case TC_CLASS:
1616                     if (type == String.class) {
1617                         throw new ClassCastException("Cannot cast a class to java.lang.String");
1618                     }
1619                     return readClass(unshared);
1620 
1621                 case TC_CLASSDESC:
1622                 case TC_PROXYCLASSDESC:
1623                     if (type == String.class) {
1624                         throw new ClassCastException("Cannot cast a class to java.lang.String");
1625                     }
1626                     return readClassDesc(unshared);
1627 
1628                 case TC_STRING:
1629                 case TC_LONGSTRING:
1630                     return checkResolve(readString(unshared));
1631 
1632                 case TC_ARRAY:
1633                     if (type == String.class) {
1634                         throw new ClassCastException("Cannot cast an array to java.lang.String");
1635                     }
1636                     return checkResolve(readArray(unshared));
1637 
1638                 case TC_ENUM:
1639                     if (type == String.class) {
1640                         throw new ClassCastException("Cannot cast an enum to java.lang.String");
1641                     }
1642                     return checkResolve(readEnum(unshared));
1643 
1644                 case TC_OBJECT:
1645                     if (type == String.class) {
1646                         throw new ClassCastException("Cannot cast an object to java.lang.String");
1647                     }
1648                     return checkResolve(readOrdinaryObject(unshared));
1649 
1650                 case TC_EXCEPTION:
1651                     if (type == String.class) {
1652                         throw new ClassCastException("Cannot cast an exception to java.lang.String");
1653                     }
1654                     IOException ex = readFatalException();
1655                     throw new WriteAbortedException("writing aborted", ex);
1656 
1657                 case TC_BLOCKDATA:
1658                 case TC_BLOCKDATALONG:
1659                     if (oldMode) {
1660                         bin.setBlockDataMode(true);
1661                         bin.peek();             // force header read
1662                         throw new OptionalDataException(
1663                             bin.currentBlockRemaining());
1664                     } else {
1665                         throw new StreamCorruptedException(
1666                             "unexpected block data");
1667                     }
1668 
1669                 case TC_ENDBLOCKDATA:
1670                     if (oldMode) {
1671                         throw new OptionalDataException(true);
1672                     } else {
1673                         throw new StreamCorruptedException(
1674                             "unexpected end of block data");
1675                     }
1676 
1677                 default:
1678                     throw new StreamCorruptedException(
1679                         String.format("invalid type code: %02X", tc));
1680             }
1681         } finally {
1682             depth--;
1683             bin.setBlockDataMode(oldMode);
1684         }
1685     }
1686 
1687     /**
1688      * If resolveObject has been enabled and given object does not have an
1689      * exception associated with it, calls resolveObject to determine
1690      * replacement for object, and updates handle table accordingly.  Returns
1691      * replacement object, or echoes provided object if no replacement
1692      * occurred.  Expects that passHandle is set to given object's handle prior
1693      * to calling this method.
1694      */
1695     private Object checkResolve(Object obj) throws IOException {
1696         if (!enableResolve || handles.lookupException(passHandle) != null) {
1697             return obj;
1698         }
1699         Object rep = resolveObject(obj);
1700         if (rep != obj) {
1701             // The type of the original object has been filtered but resolveObject
1702             // may have replaced it;  filter the replacement's type
1703             if (rep != null) {
1704                 if (rep.getClass().isArray()) {
1705                     filterCheck(rep.getClass(), Array.getLength(rep));
1706                 } else {
1707                     filterCheck(rep.getClass(), -1);
1708                 }
1709             }
1710             handles.setObject(passHandle, rep);
1711         }
1712         return rep;
1713     }
1714 
1715     /**
1716      * Reads string without allowing it to be replaced in stream.  Called from
1717      * within ObjectStreamClass.read().
1718      */
1719     String readTypeString() throws IOException {
1720         int oldHandle = passHandle;
1721         try {
1722             byte tc = bin.peekByte();
1723             return switch (tc) {
1724                 case TC_NULL                  -> (String) readNull();
1725                 case TC_REFERENCE             -> (String) readHandle(false);
1726                 case TC_STRING, TC_LONGSTRING -> readString(false);
1727                 default                       -> throw new StreamCorruptedException(
1728                         String.format("invalid type code: %02X", tc));
1729             };
1730         } finally {
1731             passHandle = oldHandle;
1732         }
1733     }
1734 
1735     /**
1736      * Reads in null code, sets passHandle to NULL_HANDLE and returns null.
1737      */
1738     private Object readNull() throws IOException {
1739         if (bin.readByte() != TC_NULL) {
1740             throw new InternalError();
1741         }
1742         passHandle = NULL_HANDLE;
1743         return null;
1744     }
1745 
1746     /**
1747      * Reads in object handle, sets passHandle to the read handle, and returns
1748      * object associated with the handle.
1749      */
1750     private Object readHandle(boolean unshared) throws IOException {
1751         if (bin.readByte() != TC_REFERENCE) {
1752             throw new InternalError();
1753         }
1754         passHandle = bin.readInt() - baseWireHandle;
1755         if (passHandle < 0 || passHandle >= handles.size()) {
1756             throw new StreamCorruptedException(
1757                 String.format("invalid handle value: %08X", passHandle +
1758                 baseWireHandle));
1759         }
1760         if (unshared) {
1761             // REMIND: what type of exception to throw here?
1762             throw new InvalidObjectException(
1763                 "cannot read back reference as unshared");
1764         }
1765 
1766         Object obj = handles.lookupObject(passHandle);
1767         if (obj == unsharedMarker) {
1768             // REMIND: what type of exception to throw here?
1769             throw new InvalidObjectException(
1770                 "cannot read back reference to unshared object");
1771         }
1772         filterCheck(null, -1);       // just a check for number of references, depth, no class
1773         return obj;
1774     }
1775 
1776     /**
1777      * Reads in and returns class object.  Sets passHandle to class object's
1778      * assigned handle.  Returns null if class is unresolvable (in which case a
1779      * ClassNotFoundException will be associated with the class' handle in the
1780      * handle table).
1781      */
1782     private Class<?> readClass(boolean unshared) throws IOException {
1783         if (bin.readByte() != TC_CLASS) {
1784             throw new InternalError();
1785         }
1786         ObjectStreamClass desc = readClassDesc(false);
1787         Class<?> cl = desc.forClass();
1788         passHandle = handles.assign(unshared ? unsharedMarker : cl);
1789 
1790         ClassNotFoundException resolveEx = desc.getResolveException();
1791         if (resolveEx != null) {
1792             handles.markException(passHandle, resolveEx);
1793         }
1794 
1795         handles.finish(passHandle);
1796         return cl;
1797     }
1798 
1799     /**
1800      * Reads in and returns (possibly null) class descriptor.  Sets passHandle
1801      * to class descriptor's assigned handle.  If class descriptor cannot be
1802      * resolved to a class in the local VM, a ClassNotFoundException is
1803      * associated with the class descriptor's handle.
1804      */
1805     private ObjectStreamClass readClassDesc(boolean unshared)
1806         throws IOException
1807     {
1808         byte tc = bin.peekByte();
1809 
1810         return switch (tc) {
1811             case TC_NULL            -> (ObjectStreamClass) readNull();
1812             case TC_PROXYCLASSDESC  -> readProxyDesc(unshared);
1813             case TC_CLASSDESC       -> readNonProxyDesc(unshared);
1814             case TC_REFERENCE       -> {
1815                 var d = (ObjectStreamClass) readHandle(unshared);
1816                 // Should only reference initialized class descriptors
1817                 d.checkInitialized();
1818                 yield d;
1819             }
1820             default                 -> throw new StreamCorruptedException(
1821                     String.format("invalid type code: %02X", tc));
1822         };
1823     }
1824 
1825     /**
1826      * Reads in and returns class descriptor for a dynamic proxy class.  Sets
1827      * passHandle to proxy class descriptor's assigned handle.  If proxy class
1828      * descriptor cannot be resolved to a class in the local VM, a
1829      * ClassNotFoundException is associated with the descriptor's handle.
1830      */
1831     private ObjectStreamClass readProxyDesc(boolean unshared)
1832         throws IOException
1833     {
1834         if (bin.readByte() != TC_PROXYCLASSDESC) {
1835             throw new InternalError();
1836         }
1837 
1838         ObjectStreamClass desc = new ObjectStreamClass();
1839         int descHandle = handles.assign(unshared ? unsharedMarker : desc);
1840         passHandle = NULL_HANDLE;
1841 
1842         int numIfaces = bin.readInt();
1843         if (numIfaces > 65535) {
1844             // Report specification limit exceeded
1845             throw new InvalidObjectException("interface limit exceeded: " +
1846                     numIfaces +
1847                     ", limit: " + Caches.PROXY_INTERFACE_LIMIT);
1848         }
1849         String[] ifaces = new String[numIfaces];
1850         for (int i = 0; i < numIfaces; i++) {
1851             ifaces[i] = bin.readUTF();
1852         }
1853 
1854         // Recheck against implementation limit and throw with interface names
1855         if (numIfaces > Caches.PROXY_INTERFACE_LIMIT) {
1856             throw new InvalidObjectException("interface limit exceeded: " +
1857                     numIfaces +
1858                     ", limit: " + Caches.PROXY_INTERFACE_LIMIT +
1859                     "; " + Arrays.toString(ifaces));
1860         }
1861         Class<?> cl = null;
1862         ClassNotFoundException resolveEx = null;
1863         bin.setBlockDataMode(true);
1864         try {
1865             if ((cl = resolveProxyClass(ifaces)) == null) {
1866                 resolveEx = new ClassNotFoundException("null class");
1867             } else if (!Proxy.isProxyClass(cl)) {
1868                 throw new InvalidClassException("Not a proxy");
1869             } else {
1870                 // Filter the interfaces
1871                 for (Class<?> clazz : cl.getInterfaces()) {
1872                     filterCheck(clazz, -1);
1873                 }
1874             }
1875         } catch (ClassNotFoundException ex) {
1876             resolveEx = ex;
1877         } catch (IllegalAccessError aie) {
1878             throw new InvalidClassException(aie.getMessage(), aie);
1879         } catch (OutOfMemoryError oome) {
1880             throw genInvalidObjectException(oome, ifaces);
1881         }
1882 
1883         // Call filterCheck on the class before reading anything else
1884         filterCheck(cl, -1);
1885 
1886         skipCustomData();
1887 
1888         try {
1889             totalObjectRefs++;
1890             depth++;
1891             desc.initProxy(cl, resolveEx, readClassDesc(false));
1892         } catch (OutOfMemoryError oome) {
1893             throw genInvalidObjectException(oome, ifaces);
1894         } finally {
1895             depth--;
1896         }
1897 
1898         handles.finish(descHandle);
1899         passHandle = descHandle;
1900         return desc;
1901     }
1902 
1903     // Generate an InvalidObjectException for an OutOfMemoryError
1904     // Use String.concat() to avoid string formatting invoke dynamic
1905     private static InvalidObjectException genInvalidObjectException(OutOfMemoryError oome,
1906                                                                     String[] ifaces) {
1907         return new InvalidObjectException("Proxy interface limit exceeded: "
1908                 .concat(Arrays.toString(ifaces)), oome);
1909     }
1910 
1911     /**
1912      * Reads in and returns class descriptor for a class that is not a dynamic
1913      * proxy class.  Sets passHandle to class descriptor's assigned handle.  If
1914      * class descriptor cannot be resolved to a class in the local VM, a
1915      * ClassNotFoundException is associated with the descriptor's handle.
1916      */
1917     private ObjectStreamClass readNonProxyDesc(boolean unshared)
1918         throws IOException
1919     {
1920         if (bin.readByte() != TC_CLASSDESC) {
1921             throw new InternalError();
1922         }
1923 
1924         ObjectStreamClass desc = new ObjectStreamClass();
1925         int descHandle = handles.assign(unshared ? unsharedMarker : desc);
1926         passHandle = NULL_HANDLE;
1927 
1928         ObjectStreamClass readDesc;
1929         try {
1930             readDesc = readClassDescriptor();
1931         } catch (ClassNotFoundException ex) {
1932             throw new InvalidClassException("failed to read class descriptor",
1933                                             ex);
1934         }
1935 
1936         Class<?> cl = null;
1937         ClassNotFoundException resolveEx = null;
1938         bin.setBlockDataMode(true);
1939         try {
1940             if ((cl = resolveClass(readDesc)) == null) {
1941                 resolveEx = new ClassNotFoundException("null class");
1942             }
1943         } catch (ClassNotFoundException ex) {
1944             resolveEx = ex;
1945         }
1946 
1947         // Call filterCheck on the class before reading anything else
1948         filterCheck(cl, -1);
1949 
1950         skipCustomData();
1951 
1952         try {
1953             totalObjectRefs++;
1954             depth++;
1955             desc.initNonProxy(readDesc, cl, resolveEx, readClassDesc(false));
1956 
1957             if (cl != null) {
1958                 // Check that serial filtering has been done on the local class descriptor's superclass,
1959                 // in case it does not appear in the stream.
1960 
1961                 // Find the next super descriptor that has a local class descriptor.
1962                 // Descriptors for which there is no local class are ignored.
1963                 ObjectStreamClass superLocal = null;
1964                 for (ObjectStreamClass sDesc = desc.getSuperDesc(); sDesc != null; sDesc = sDesc.getSuperDesc()) {
1965                     if ((superLocal = sDesc.getLocalDesc()) != null) {
1966                         break;
1967                     }
1968                 }
1969 
1970                 // Scan local descriptor superclasses for a match with the local descriptor of the super found above.
1971                 // For each super descriptor before the match, invoke the serial filter on the class.
1972                 // The filter is invoked for each class that has not already been filtered
1973                 // but would be filtered if the instance had been serialized by this Java runtime.
1974                 for (ObjectStreamClass lDesc = desc.getLocalDesc().getSuperDesc();
1975                      lDesc != null && lDesc != superLocal;
1976                      lDesc = lDesc.getSuperDesc()) {
1977                     filterCheck(lDesc.forClass(), -1);
1978                 }
1979             }
1980         } finally {
1981             depth--;
1982         }
1983 
1984         handles.finish(descHandle);
1985         passHandle = descHandle;
1986 
1987         return desc;
1988     }
1989 
1990     /**
1991      * Reads in and returns new string.  Sets passHandle to new string's
1992      * assigned handle.
1993      */
1994     private String readString(boolean unshared) throws IOException {
1995         byte tc = bin.readByte();
1996         String str = switch (tc) {
1997             case TC_STRING      -> bin.readUTF();
1998             case TC_LONGSTRING  -> bin.readLongUTF();
1999             default             -> throw new StreamCorruptedException(
2000                     String.format("invalid type code: %02X", tc));
2001         };
2002         passHandle = handles.assign(unshared ? unsharedMarker : str);
2003         handles.finish(passHandle);
2004         return str;
2005     }
2006 
2007     /**
2008      * Reads in and returns array object, or null if array class is
2009      * unresolvable.  Sets passHandle to array's assigned handle.
2010      */
2011     private Object readArray(boolean unshared) throws IOException {
2012         if (bin.readByte() != TC_ARRAY) {
2013             throw new InternalError();
2014         }
2015 
2016         ObjectStreamClass desc = readClassDesc(false);
2017         int len = bin.readInt();
2018         if (len < 0) {
2019             throw new StreamCorruptedException("Array length is negative");
2020         }
2021         filterCheck(desc.forClass(), len);
2022 
2023         Object array = null;
2024         Class<?> cl, ccl = null;
2025         if ((cl = desc.forClass()) != null) {
2026             ccl = cl.getComponentType();
2027             array = Array.newInstance(ccl, len);
2028         }
2029 
2030         int arrayHandle = handles.assign(unshared ? unsharedMarker : array);
2031         ClassNotFoundException resolveEx = desc.getResolveException();
2032         if (resolveEx != null) {
2033             handles.markException(arrayHandle, resolveEx);
2034         }
2035 
2036         if (ccl == null) {
2037             for (int i = 0; i < len; i++) {
2038                 readObject0(Object.class, false);
2039             }
2040         } else if (ccl.isPrimitive()) {
2041             if (ccl == Integer.TYPE) {
2042                 bin.readInts((int[]) array, 0, len);
2043             } else if (ccl == Byte.TYPE) {
2044                 bin.readFully((byte[]) array, 0, len, true);
2045             } else if (ccl == Long.TYPE) {
2046                 bin.readLongs((long[]) array, 0, len);
2047             } else if (ccl == Float.TYPE) {
2048                 bin.readFloats((float[]) array, 0, len);
2049             } else if (ccl == Double.TYPE) {
2050                 bin.readDoubles((double[]) array, 0, len);
2051             } else if (ccl == Short.TYPE) {
2052                 bin.readShorts((short[]) array, 0, len);
2053             } else if (ccl == Character.TYPE) {
2054                 bin.readChars((char[]) array, 0, len);
2055             } else if (ccl == Boolean.TYPE) {
2056                 bin.readBooleans((boolean[]) array, 0, len);
2057             } else {
2058                 throw new InternalError();
2059             }
2060         } else {
2061             Object[] oa = (Object[]) array;
2062             for (int i = 0; i < len; i++) {
2063                 oa[i] = readObject0(Object.class, false);
2064                 handles.markDependency(arrayHandle, passHandle);
2065             }
2066         }
2067 
2068         handles.finish(arrayHandle);
2069         passHandle = arrayHandle;
2070         return array;
2071     }
2072 
2073     /**
2074      * Reads in and returns enum constant, or null if enum type is
2075      * unresolvable.  Sets passHandle to enum constant's assigned handle.
2076      */
2077     private Enum<?> readEnum(boolean unshared) throws IOException {
2078         if (bin.readByte() != TC_ENUM) {
2079             throw new InternalError();
2080         }
2081 
2082         ObjectStreamClass desc = readClassDesc(false);
2083         if (!desc.isEnum()) {
2084             throw new InvalidClassException("non-enum class: " + desc);
2085         }
2086 
2087         int enumHandle = handles.assign(unshared ? unsharedMarker : null);
2088         ClassNotFoundException resolveEx = desc.getResolveException();
2089         if (resolveEx != null) {
2090             handles.markException(enumHandle, resolveEx);
2091         }
2092 
2093         String name = readString(false);
2094         Enum<?> result = null;
2095         Class<?> cl = desc.forClass();
2096         if (cl != null) {
2097             try {
2098                 @SuppressWarnings("unchecked")
2099                 Enum<?> en = Enum.valueOf((Class)cl, name);
2100                 result = en;
2101             } catch (IllegalArgumentException ex) {
2102                 throw new InvalidObjectException("enum constant " +
2103                                                  name + " does not exist in " + cl, ex);
2104             }
2105             if (!unshared) {
2106                 handles.setObject(enumHandle, result);
2107             }
2108         }
2109 
2110         handles.finish(enumHandle);
2111         passHandle = enumHandle;
2112         return result;
2113     }
2114 
2115     /**
2116      * Reads and returns "ordinary" (i.e., not a String, Class,
2117      * ObjectStreamClass, array, or enum constant) object, or null if object's
2118      * class is unresolvable (in which case a ClassNotFoundException will be
2119      * associated with object's handle).  Sets passHandle to object's assigned
2120      * handle.
2121      */
2122     private Object readOrdinaryObject(boolean unshared)
2123         throws IOException
2124     {
2125         if (bin.readByte() != TC_OBJECT) {
2126             throw new InternalError();
2127         }
2128 
2129         ObjectStreamClass desc = readClassDesc(false);
2130         desc.checkDeserialize();
2131 
2132         Class<?> cl = desc.forClass();
2133         if (cl == String.class || cl == Class.class
2134                 || cl == ObjectStreamClass.class) {
2135             throw new InvalidClassException("invalid class descriptor");
2136         }
2137 
2138         // Assign the handle and initially set to null or the unsharedMarker
2139         passHandle = handles.assign(unshared ? unsharedMarker : null);
2140         ClassNotFoundException resolveEx = desc.getResolveException();
2141         if (resolveEx != null) {
2142             handles.markException(passHandle, resolveEx);
2143         }
2144 
2145         try {
2146             // Dispatch on the factory mode to read an object from the stream.
2147             Object obj = switch (desc.factoryMode()) {
2148                 case READ_OBJECT_DEFAULT -> readSerialDefaultObject(desc, unshared);
2149                 case READ_OBJECT_CUSTOM -> readSerialCustomData(desc, unshared);
2150                 case READ_RECORD -> readRecord(desc, unshared);
2151                 case READ_EXTERNALIZABLE -> readExternalObject(desc, unshared);
2152                 case READ_OBJECT_VALUE -> readObjectValue(desc, unshared);
2153                 case READ_NO_LOCAL_CLASS -> readAbsentLocalClass(desc, unshared);
2154                 case null -> throw new AssertionError("Unknown factoryMode for: " + desc.getName(),
2155                         resolveEx);
2156             };
2157 
2158             handles.finish(passHandle);
2159 
2160             if (obj != null &&
2161                 handles.lookupException(passHandle) == null &&
2162                 desc.hasReadResolveMethod())
2163             {
2164                 Object rep = desc.invokeReadResolve(obj);
2165                 if (unshared && rep.getClass().isArray()) {
2166                     rep = cloneArray(rep);
2167                 }
2168                 if (rep != obj) {
2169                     // Filter the replacement object
2170                     if (rep != null) {
2171                         if (rep.getClass().isArray()) {
2172                             filterCheck(rep.getClass(), Array.getLength(rep));
2173                         } else {
2174                             filterCheck(rep.getClass(), -1);
2175                         }
2176                     }
2177                     handles.setObject(passHandle, obj = rep);
2178                 }
2179             }
2180 
2181             return obj;
2182         } catch (UncheckedIOException uioe) {
2183             // Consistent re-throw for nested UncheckedIOExceptions
2184             throw uioe.getCause();
2185         }
2186     }
2187 
2188     /**
2189      * {@return a value class instance by invoking its constructor with field values read from the stream.
2190      * The fields of the class in the stream are matched to the local fields and applied to
2191      * the constructor.
2192      * If the stream contains superclasses with serializable fields,
2193      * an InvalidClassException is thrown with an incompatible class change message.
2194      *
2195      * @param desc the class descriptor read from the stream, the local class is a value class
2196      * @param unshared if the object is not to be shared
2197      * @throws InvalidClassException if the stream contains a superclass with serializable fields.
2198      * @throws IOException if there are I/O errors while reading from the
2199      *         underlying {@code InputStream}
2200      */
2201     private Object readObjectValue(ObjectStreamClass desc, boolean unshared) throws IOException {
2202         final ObjectStreamClass localDesc = desc.getLocalDesc();
2203         TRACE("readObjectValue: %s, local class: %s", desc.getName(), localDesc.getName());
2204         // Check for un-expected fields in superclasses
2205         List<ClassDataSlot> slots = desc.getClassDataLayout();
2206         for (int i = 0; i < slots.size()-1; i++) {
2207             ClassDataSlot slot = slots.get(i);
2208             if (slot.hasData && slot.desc.getFields(false).length > 0) {
2209                 throw new InvalidClassException("incompatible class change to value class: " +
2210                         "stream class has non-empty super type: " + desc.getName());
2211             }
2212         }
2213         // Read values for the value class fields
2214         FieldValues fieldValues = new FieldValues(desc, true);
2215 
2216         // Get value object constructor adapted to take primitive value buffer and object array.
2217         MethodHandle consMH = ConstructorSupport.deserializationValueCons(desc);
2218         try {
2219             Object obj = (Object) consMH.invokeExact(fieldValues.primValues, fieldValues.objValues);
2220             if (!unshared)
2221                 handles.setObject(passHandle, obj);
2222             return obj;
2223         } catch (Exception e) {
2224             throw new InvalidObjectException(e.getMessage(), e);
2225         } catch (Error e) {
2226             throw e;
2227         } catch (Throwable t) {
2228             throw new InvalidObjectException("ReflectiveOperationException " +
2229                     "during deserialization", t);
2230         }
2231     }
2232 
2233     /**
2234      * Creates a new object and invokes its readExternal method to read its contents.
2235      *
2236      * If the class is instantiable, read externalizable data by invoking readExternal()
2237      * method of obj; otherwise, attempts to skip over externalizable data.
2238      * Expects that passHandle is set to obj's handle before this method is
2239      * called.  The new object is entered in the handle table immediately,
2240      * allowing it to leak before it is completely read.
2241      */
2242     private Object readExternalObject(ObjectStreamClass desc, boolean unshared)
2243         throws IOException
2244     {
2245         TRACE("readExternalObject: %s", desc.getName());
2246 
2247         // For Externalizable objects,
2248         // create the instance, publish the ref, and read the data
2249         Externalizable obj = null;
2250         try {
2251             if (desc.isInstantiable()) {
2252                 obj = (Externalizable) desc.newInstance();
2253             }
2254         } catch (Exception ex) {
2255             throw new InvalidClassException(desc.getName(),
2256                     "unable to create instance", ex);
2257         }
2258 
2259         if (!unshared)
2260             handles.setObject(passHandle, obj);
2261 
2262         SerialCallbackContext oldContext = curContext;
2263         if (oldContext != null)
2264             oldContext.check();
2265         curContext = null;
2266         try {
2267             boolean blocked = desc.hasBlockExternalData();
2268             if (blocked) {
2269                 bin.setBlockDataMode(true);
2270             }
2271             if (obj != null) {
2272                 try {
2273                     obj.readExternal(this);
2274                 } catch (ClassNotFoundException ex) {
2275                     /*
2276                      * In most cases, the handle table has already propagated
2277                      * a CNFException to passHandle at this point; this mark
2278                      * call is included to address cases where the readExternal
2279                      * method has cons'ed and thrown a new CNFException of its
2280                      * own.
2281                      */
2282                      handles.markException(passHandle, ex);
2283                 }
2284             }
2285             if (blocked) {
2286                 skipCustomData();
2287             }
2288         } finally {
2289             if (oldContext != null)
2290                 oldContext.check();
2291             curContext = oldContext;
2292         }
2293         /*
2294          * At this point, if the externalizable data was not written in
2295          * block-data form and either the externalizable class doesn't exist
2296          * locally (i.e., obj == null) or readExternal() just threw a
2297          * CNFException, then the stream is probably in an inconsistent state,
2298          * since some (or all) of the externalizable data may not have been
2299          * consumed.  Since there's no "correct" action to take in this case,
2300          * we mimic the behavior of past serialization implementations and
2301          * blindly hope that the stream is in sync; if it isn't and additional
2302          * externalizable data remains in the stream, a subsequent read will
2303          * most likely throw a StreamCorruptedException.
2304          */
2305         return obj;
2306     }
2307 
2308     /**
2309      * Reads and returns a record.
2310      * If an exception is marked for any of the fields, the dependency
2311      * mechanism marks the record as having an exception.
2312      * Null is returned from readRecord and later the exception is thrown at
2313      * the exit of {@link #readObject(Class)}.
2314      */
2315     private Object readRecord(ObjectStreamClass desc, boolean unshared) throws IOException {
2316         TRACE("invoking readRecord: %s", desc.getName());
2317         List<ClassDataSlot> slots = desc.getClassDataLayout();
2318         if (slots.size() != 1) {
2319             // skip any superclass stream field values
2320             for (int i = 0; i < slots.size()-1; i++) {
2321                 if (slots.get(i).hasData) {
2322                     new FieldValues(slots.get(i).desc, true);
2323                 }
2324             }
2325         }
2326 
2327         FieldValues fieldValues = new FieldValues(desc, true);
2328         if (handles.lookupException(passHandle) != null) {
2329             return null;     // slot marked with exception, don't create record
2330         }
2331 
2332         // get canonical record constructor adapted to take two arguments:
2333         // - byte[] primValues
2334         // - Object[] objValues
2335         // and return Object
2336         MethodHandle ctrMH = ConstructorSupport.deserializationCtr(desc);
2337 
2338         try {
2339             Object obj = (Object) ctrMH.invokeExact(fieldValues.primValues, fieldValues.objValues);
2340             if (!unshared)
2341                 handles.setObject(passHandle, obj);
2342             return obj;
2343         } catch (Exception e) {
2344             throw new InvalidObjectException(e.getMessage(), e);
2345         } catch (Error e) {
2346             throw e;
2347         } catch (Throwable t) {
2348             throw new InvalidObjectException("ReflectiveOperationException " +
2349                                              "during deserialization", t);
2350         }
2351     }
2352 
2353     /**
2354      * Construct an object from the stream for a class that has only default read object behaviors.
2355      * For each object, the fields are read before any are assigned.
2356      * The new instance is entered in the handle table if it is unshared,
2357      * allowing it to escape before it is initialized.
2358      * The `readObject` and `readObjectNoData` methods are not present and are not called.
2359      *
2360      * @param desc the class descriptor
2361      * @param unshared true if the object should be shared
2362      * @return the object constructed from the stream data
2363      * @throws IOException if there are I/O errors while reading from the
2364      *         underlying {@code InputStream}
2365      * @throws InvalidClassException if the instance creation fails
2366      */
2367     private Object readSerialDefaultObject(ObjectStreamClass desc, boolean unshared)
2368             throws IOException, InvalidClassException {
2369         if (!desc.isInstantiable()) {
2370             // No local class to create, read and discard
2371             return readAbsentLocalClass(desc, unshared);
2372         }
2373         TRACE("readSerialDefaultObject: %s", desc.getName());
2374         try {
2375             final Object obj = desc.newInstance();
2376             if (!unshared)
2377                 handles.setObject(passHandle, obj);
2378 
2379             // Best effort Failure Atomicity; slotValues will be non-null if field
2380             // values can be set after reading all field data in the hierarchy.
2381             List<FieldValues> slotValues = desc.getClassDataLayout().stream()
2382                     .filter(s -> s.hasData)
2383                     .map(s1 -> {
2384                         var values = new FieldValues(s1.desc, true);
2385                         finishBlockData(s1.desc);
2386                         return values;
2387                     })
2388                     .toList();
2389 
2390             if (handles.lookupException(passHandle) != null) {
2391                 return null;    // some exception for a class, do not return the object
2392             }
2393 
2394             // Check that the types are assignable for all slots before assigning.
2395             slotValues.forEach(v -> v.defaultCheckFieldValues(obj));
2396             slotValues.forEach(v -> v.defaultSetFieldValues(obj));
2397             return obj;
2398         } catch (InstantiationException | InvocationTargetException ex) {
2399             throw new InvalidClassException(desc.forClass().getName(),
2400                     "unable to create instance", ex);
2401         }
2402     }
2403 
2404 
2405     /**
2406      * Reads (or attempts to skip, if not instantiatable or is tagged with a
2407      * ClassNotFoundException) instance data for each serializable class of
2408      * object in stream, from superclass to subclass.
2409      * Expects that passHandle is set to current handle before this method is called.
2410      */
2411     private Object readSerialCustomData(ObjectStreamClass desc, boolean unshared)
2412         throws IOException
2413     {
2414         if (!desc.isInstantiable()) {
2415             // No local class to create, read and discard
2416             return readAbsentLocalClass(desc, unshared);
2417         }
2418 
2419         TRACE("readSerialCustomData: %s, ex: %s", desc.getName(), handles.lookupException(passHandle));
2420         try {
2421             Object obj = desc.newInstance();
2422             if (!unshared)
2423                 handles.setObject(passHandle, obj);
2424             // Read data into each of the slots for the class
2425             return readSerialCustomSlots(obj, desc.getClassDataLayout());
2426         } catch (InstantiationException | InvocationTargetException ex) {
2427             throw new InvalidClassException(desc.forClass().getName(),
2428                     "unable to create instance", ex);
2429         }
2430     }
2431 
2432     /**
2433      * Reads from the stream using custom or default readObject methods appropriate.
2434      * For each slot, either the custom readObject method or the default reader of fields
2435      * is invoked. Unused slot specific custom data is discarded.
2436      * This function is used by {@link #readSerialCustomData}.
2437      *
2438      * @param obj the object to assign the values to
2439      * @param slots a list of slots to read from the stream
2440      * @return the object being initialized
2441      * @throws IOException if there are I/O errors while reading from the
2442      *         underlying {@code InputStream}
2443      */
2444     private Object readSerialCustomSlots(Object obj, List<ClassDataSlot> slots) throws IOException {
2445         TRACE("    readSerialCustomSlots: %s", slots);
2446 
2447         for (ClassDataSlot slot : slots) {
2448             ObjectStreamClass slotDesc = slot.desc;
2449             if (slot.hasData) {
2450                 if (slotDesc.hasReadObjectMethod() &&
2451                         handles.lookupException(passHandle) == null) {
2452                     // Invoke slot custom readObject method
2453                     readSlotViaReadObject(obj, slotDesc);
2454                 } else {
2455                     // Read fields of the current descriptor into a new FieldValues
2456                     FieldValues values = new FieldValues(slotDesc, true);
2457                     if (handles.lookupException(passHandle) == null) {
2458                         // Set the instance fields if no previous exception
2459                         values.defaultCheckFieldValues(obj);
2460                         values.defaultSetFieldValues(obj);
2461                     }
2462                     finishBlockData(slotDesc);
2463                 }
2464             } else {
2465                 if (slotDesc.hasReadObjectNoDataMethod() &&
2466                         handles.lookupException(passHandle) == null) {
2467                     slotDesc.invokeReadObjectNoData(obj);
2468                 }
2469             }
2470         }
2471         return obj;
2472     }
2473 
2474     /**
2475      * Invoke the readObject method of the class to read and store the state from the stream.
2476      *
2477      * @param obj an instance of the class being created, only partially initialized.
2478      * @param slotDesc the ObjectStreamDescriptor for the current class
2479      * @throws IOException if there are I/O errors while reading from the
2480      *         underlying {@code InputStream}
2481      */
2482     private void readSlotViaReadObject(Object obj, ObjectStreamClass slotDesc) throws IOException {
2483         TRACE("readSlotViaReadObject: %s", slotDesc.getName());
2484         assert obj != null : "readSlotViaReadObject called when obj == null";
2485 
2486         SerialCallbackContext oldContext = curContext;
2487         if (oldContext != null)
2488             oldContext.check();
2489         try {
2490             curContext = new SerialCallbackContext(obj, slotDesc);
2491 
2492             bin.setBlockDataMode(true);
2493             slotDesc.invokeReadObject(obj, this);
2494         } catch (ClassNotFoundException ex) {
2495             /*
2496              * In most cases, the handle table has already
2497              * propagated a CNFException to passHandle at this
2498              * point; this mark call is included to address cases
2499              * where the custom readObject method has cons'ed and
2500              * thrown a new CNFException of its own.
2501              */
2502             handles.markException(passHandle, ex);
2503         } finally {
2504             curContext.setUsed();
2505             if (oldContext!= null)
2506                 oldContext.check();
2507             curContext = oldContext;
2508         }
2509 
2510         /*
2511          * defaultDataEnd may have been set indirectly by custom
2512          * readObject() method when calling defaultReadObject() or
2513          * readFields(); clear it to restore normal read behavior.
2514          */
2515         defaultDataEnd = false;
2516 
2517         finishBlockData(slotDesc);
2518     }
2519 
2520 
2521     /**
2522      * Read and discard an entire object, leaving a null reference in the HandleTable.
2523      * The descriptor of the class in the stream is used to read the fields from the stream.
2524      * There is no instance in which to store the field values.
2525      * Custom data following the fields of any slot is read and discarded.
2526      * References to nested objects are read and retained in the
2527      * handle table using the regular mechanism.
2528      * Handles later in the stream may refer to the nested objects.
2529      *
2530      * @param desc the stream class descriptor
2531      * @param unshared the unshared flag, ignored since no object is created
2532      * @return null, no object is created
2533      * @throws IOException if there are I/O errors while reading from the
2534      *         underlying {@code InputStream}
2535      */
2536     private Object readAbsentLocalClass(ObjectStreamClass desc, boolean unshared)
2537             throws IOException {
2538         TRACE("readAbsentLocalClass: %s", desc.getName());
2539         desc.getClassDataLayout().stream()
2540                 .filter(s -> s.hasData)
2541                 .forEach(s2 -> {new FieldValues(s2.desc, true); finishBlockData(s2.desc);});
2542         return null;
2543     }
2544 
2545     // Finish handling of block data by skipping any remaining and setting BlockDataMode = false
2546     private void finishBlockData(ObjectStreamClass slotDesc) throws UncheckedIOException {
2547         try {
2548             if (slotDesc.hasWriteObjectData()) {
2549                 skipCustomData();
2550             } else {
2551                 bin.setBlockDataMode(false);
2552             }
2553         } catch (IOException ioe) {
2554             throw new UncheckedIOException(ioe);
2555         }
2556     }
2557 
2558     /**
2559      * Skips over all block data and objects until TC_ENDBLOCKDATA is
2560      * encountered.
2561      */
2562     private void skipCustomData() throws IOException {
2563         int oldHandle = passHandle;
2564         for (;;) {
2565             if (bin.getBlockDataMode()) {
2566                 bin.skipBlockData();
2567                 bin.setBlockDataMode(false);
2568             }
2569             switch (bin.peekByte()) {
2570                 case TC_BLOCKDATA:
2571                 case TC_BLOCKDATALONG:
2572                     bin.setBlockDataMode(true);
2573                     break;
2574 
2575                 case TC_ENDBLOCKDATA:
2576                     bin.readByte();
2577                     passHandle = oldHandle;
2578                     return;
2579 
2580                 default:
2581                     readObject0(Object.class, false);
2582                     break;
2583             }
2584         }
2585     }
2586 
2587     /**
2588      * Reads in and returns IOException that caused serialization to abort.
2589      * All stream state is discarded prior to reading in fatal exception.  Sets
2590      * passHandle to fatal exception's handle.
2591      */
2592     private IOException readFatalException() throws IOException {
2593         if (bin.readByte() != TC_EXCEPTION) {
2594             throw new InternalError();
2595         }
2596         clear();
2597         // Check that an object follows the TC_EXCEPTION typecode
2598         byte tc = bin.peekByte();
2599         if (tc != TC_OBJECT &&
2600             tc != TC_REFERENCE) {
2601             throw new StreamCorruptedException(
2602                     String.format("invalid type code: %02X", tc));
2603         }
2604         return (IOException) readObject0(Object.class, false);
2605     }
2606 
2607     /**
2608      * If recursion depth is 0, clears internal data structures; otherwise,
2609      * throws a StreamCorruptedException.  This method is called when a
2610      * TC_RESET typecode is encountered.
2611      */
2612     private void handleReset() throws StreamCorruptedException {
2613         if (depth > 0) {
2614             throw new StreamCorruptedException(
2615                 "unexpected reset; recursion depth: " + depth);
2616         }
2617         clear();
2618     }
2619 
2620     /**
2621      * Returns the first non-null and non-platform class loader (not counting
2622      * class loaders of generated reflection implementation classes) up the
2623      * execution stack, or the platform class loader if only code from the
2624      * bootstrap and platform class loader is on the stack.
2625      */
2626     private static ClassLoader latestUserDefinedLoader() {
2627         return jdk.internal.misc.VM.latestUserDefinedLoader();
2628     }
2629 
2630     /**
2631      * Default GetField implementation.
2632      */
2633     private final class FieldValues extends GetField {
2634 
2635         /** class descriptor describing serializable fields */
2636         private final ObjectStreamClass desc;
2637         /** primitive field values */
2638         final byte[] primValues;
2639         /** object field values */
2640         final Object[] objValues;
2641         /** object field value handles */
2642         private final int[] objHandles;
2643 
2644         /**
2645          * Creates FieldValues object for reading fields defined in given
2646          * class descriptor.
2647          * @param desc the ObjectStreamClass to read
2648          * @param recordDependencies if true, record the dependencies
2649          *                           from current PassHandle and the object's read.
2650          * @throws UncheckedIOException if any IOException occurs
2651          */
2652         FieldValues(ObjectStreamClass desc, boolean recordDependencies) throws UncheckedIOException {
2653             try {
2654                 this.desc = desc;
2655                 TRACE("    reading FieldValues: %s", desc.getName());
2656                 int primDataSize = desc.getPrimDataSize();
2657                 primValues = (primDataSize > 0) ? new byte[primDataSize] : null;
2658                 if (primDataSize > 0) {
2659                     bin.readFully(primValues, 0, primDataSize, false);
2660                 }
2661 
2662 
2663                 int numObjFields = desc.getNumObjFields();
2664                 objValues = (numObjFields > 0) ? new Object[numObjFields] : null;
2665                 objHandles = (numObjFields > 0) ? new int[numObjFields] : null;
2666                 if (numObjFields > 0) {
2667                     int objHandle = passHandle;
2668                     ObjectStreamField[] fields = desc.getFields(false);
2669                     int numPrimFields = fields.length - objValues.length;
2670                     for (int i = 0; i < objValues.length; i++) {
2671                         ObjectStreamField f = fields[numPrimFields + i];
2672                         objValues[i] = readObject0(Object.class, f.isUnshared());
2673                         objHandles[i] = passHandle;
2674                         if (recordDependencies && f.getField() != null) {
2675                             handles.markDependency(objHandle, passHandle);
2676                         }
2677                     }
2678                     passHandle = objHandle;
2679                 }
2680             } catch (IOException ioe) {
2681                 throw new UncheckedIOException(ioe);
2682             }
2683         }
2684 
2685         public ObjectStreamClass getObjectStreamClass() {
2686             return desc;
2687         }
2688 
2689         public boolean defaulted(String name) {
2690             return (getFieldOffset(name, null) < 0);
2691         }
2692 
2693         public boolean get(String name, boolean val) {
2694             int off = getFieldOffset(name, Boolean.TYPE);
2695             return (off >= 0) ? ByteArray.getBoolean(primValues, off) : val;
2696         }
2697 
2698         public byte get(String name, byte val) {
2699             int off = getFieldOffset(name, Byte.TYPE);
2700             return (off >= 0) ? primValues[off] : val;
2701         }
2702 
2703         public char get(String name, char val) {
2704             int off = getFieldOffset(name, Character.TYPE);
2705             return (off >= 0) ? ByteArray.getChar(primValues, off) : val;
2706         }
2707 
2708         public short get(String name, short val) {
2709             int off = getFieldOffset(name, Short.TYPE);
2710             return (off >= 0) ? ByteArray.getShort(primValues, off) : val;
2711         }
2712 
2713         public int get(String name, int val) {
2714             int off = getFieldOffset(name, Integer.TYPE);
2715             return (off >= 0) ? ByteArray.getInt(primValues, off) : val;
2716         }
2717 
2718         public float get(String name, float val) {
2719             int off = getFieldOffset(name, Float.TYPE);
2720             return (off >= 0) ? ByteArray.getFloat(primValues, off) : val;
2721         }
2722 
2723         public long get(String name, long val) {
2724             int off = getFieldOffset(name, Long.TYPE);
2725             return (off >= 0) ? ByteArray.getLong(primValues, off) : val;
2726         }
2727 
2728         public double get(String name, double val) {
2729             int off = getFieldOffset(name, Double.TYPE);
2730             return (off >= 0) ? ByteArray.getDouble(primValues, off) : val;
2731         }
2732 
2733         public Object get(String name, Object val) throws ClassNotFoundException {
2734             int off = getFieldOffset(name, Object.class);
2735             if (off >= 0) {
2736                 int objHandle = objHandles[off];
2737                 handles.markDependency(passHandle, objHandle);
2738                 ClassNotFoundException ex = handles.lookupException(objHandle);
2739                 if (ex == null)
2740                     return objValues[off];
2741                 if (Caches.GETFIELD_CNFE_RETURNS_NULL) {
2742                     // Revert to the prior behavior; return null instead of CNFE
2743                     return null;
2744                 }
2745                 throw ex;
2746             } else {
2747                 return val;
2748             }
2749         }
2750 
2751         /** Throws ClassCastException if any value is not assignable. */
2752         void defaultCheckFieldValues(Object obj) {
2753             if (objValues != null)
2754                 desc.checkObjFieldValueTypes(obj, objValues);
2755         }
2756 
2757         private void defaultSetFieldValues(Object obj) {
2758             if (primValues != null)
2759                 desc.setPrimFieldValues(obj, primValues);
2760             if (objValues != null)
2761                 desc.setObjFieldValues(obj, objValues);
2762         }
2763 
2764         /**
2765          * Returns offset of field with given name and type.  A specified type
2766          * of null matches all types, Object.class matches all non-primitive
2767          * types, and any other non-null type matches assignable types only.
2768          * If no matching field is found in the (incoming) class
2769          * descriptor but a matching field is present in the associated local
2770          * class descriptor, returns -1.  Throws IllegalArgumentException if
2771          * neither incoming nor local class descriptor contains a match.
2772          */
2773         private int getFieldOffset(String name, Class<?> type) {
2774             ObjectStreamField field = desc.getField(name, type);
2775             if (field != null) {
2776                 return field.getOffset();
2777             } else if (desc.getLocalDesc().getField(name, type) != null) {
2778                 return -1;
2779             } else {
2780                 throw new IllegalArgumentException("no such field " + name +
2781                                                    " with type " + type);
2782             }
2783         }
2784     }
2785 
2786     /**
2787      * Prioritized list of callbacks to be performed once object graph has been
2788      * completely deserialized.
2789      */
2790     private static class ValidationList {
2791 
2792         private static class Callback {
2793             final ObjectInputValidation obj;
2794             final int priority;
2795             Callback next;
2796 
2797             Callback(ObjectInputValidation obj, int priority, Callback next) {
2798                 this.obj = obj;
2799                 this.priority = priority;
2800                 this.next = next;
2801             }
2802         }
2803 
2804         /** linked list of callbacks */
2805         private Callback list;
2806 
2807         /**
2808          * Creates new (empty) ValidationList.
2809          */
2810         ValidationList() {
2811         }
2812 
2813         /**
2814          * Registers callback.  Throws InvalidObjectException if callback
2815          * object is null.
2816          */
2817         void register(ObjectInputValidation obj, int priority)
2818             throws InvalidObjectException
2819         {
2820             if (obj == null) {
2821                 throw new InvalidObjectException("null callback");
2822             }
2823 
2824             Callback prev = null, cur = list;
2825             while (cur != null && priority < cur.priority) {
2826                 prev = cur;
2827                 cur = cur.next;
2828             }
2829             if (prev != null) {
2830                 prev.next = new Callback(obj, priority, cur);
2831             } else {
2832                 list = new Callback(obj, priority, list);
2833             }
2834         }
2835 
2836         /**
2837          * Invokes all registered callbacks and clears the callback list.
2838          * Callbacks with higher priorities are called first; those with equal
2839          * priorities may be called in any order.  If any of the callbacks
2840          * throws an InvalidObjectException, the callback process is terminated
2841          * and the exception propagated upwards.
2842          */
2843         void doCallbacks() throws InvalidObjectException {
2844             try {
2845                 while (list != null) {
2846                     list.obj.validateObject();
2847                     list = list.next;
2848                 }
2849             } catch (InvalidObjectException ex) {
2850                 list = null;
2851                 throw ex;
2852             }
2853         }
2854 
2855         /**
2856          * Resets the callback list to its initial (empty) state.
2857          */
2858         public void clear() {
2859             list = null;
2860         }
2861     }
2862 
2863     /**
2864      * Hold a snapshot of values to be passed to an ObjectInputFilter.
2865      */
2866     static class FilterValues implements ObjectInputFilter.FilterInfo {
2867         final Class<?> clazz;
2868         final long arrayLength;
2869         final long totalObjectRefs;
2870         final long depth;
2871         final long streamBytes;
2872 
2873         public FilterValues(Class<?> clazz, long arrayLength, long totalObjectRefs,
2874                             long depth, long streamBytes) {
2875             this.clazz = clazz;
2876             this.arrayLength = arrayLength;
2877             this.totalObjectRefs = totalObjectRefs;
2878             this.depth = depth;
2879             this.streamBytes = streamBytes;
2880         }
2881 
2882         @Override
2883         public Class<?> serialClass() {
2884             return clazz;
2885         }
2886 
2887         @Override
2888         public long arrayLength() {
2889             return arrayLength;
2890         }
2891 
2892         @Override
2893         public long references() {
2894             return totalObjectRefs;
2895         }
2896 
2897         @Override
2898         public long depth() {
2899             return depth;
2900         }
2901 
2902         @Override
2903         public long streamBytes() {
2904             return streamBytes;
2905         }
2906     }
2907 
2908     /**
2909      * Input stream supporting single-byte peek operations.
2910      */
2911     private static class PeekInputStream extends InputStream {
2912 
2913         /** underlying stream */
2914         private final InputStream in;
2915         /** peeked byte */
2916         private int peekb = -1;
2917         /** total bytes read from the stream */
2918         private long totalBytesRead = 0;
2919 
2920         /**
2921          * Creates new PeekInputStream on top of given underlying stream.
2922          */
2923         PeekInputStream(InputStream in) {
2924             this.in = in;
2925         }
2926 
2927         /**
2928          * Peeks at next byte value in stream.  Similar to read(), except
2929          * that it does not consume the read value.
2930          */
2931         int peek() throws IOException {
2932             if (peekb >= 0) {
2933                 return peekb;
2934             }
2935             peekb = in.read();
2936             totalBytesRead += peekb >= 0 ? 1 : 0;
2937             return peekb;
2938         }
2939 
2940         public int read() throws IOException {
2941             if (peekb >= 0) {
2942                 int v = peekb;
2943                 peekb = -1;
2944                 return v;
2945             } else {
2946                 int nbytes = in.read();
2947                 totalBytesRead += nbytes >= 0 ? 1 : 0;
2948                 return nbytes;
2949             }
2950         }
2951 
2952         public int read(byte[] b, int off, int len) throws IOException {
2953             int nbytes;
2954             if (len == 0) {
2955                 return 0;
2956             } else if (peekb < 0) {
2957                 nbytes = in.read(b, off, len);
2958                 totalBytesRead += nbytes >= 0 ? nbytes : 0;
2959                 return nbytes;
2960             } else {
2961                 b[off++] = (byte) peekb;
2962                 len--;
2963                 peekb = -1;
2964                 nbytes = in.read(b, off, len);
2965                 totalBytesRead += nbytes >= 0 ? nbytes : 0;
2966                 return (nbytes >= 0) ? (nbytes + 1) : 1;
2967             }
2968         }
2969 
2970         void readFully(byte[] b, int off, int len) throws IOException {
2971             int n = 0;
2972             while (n < len) {
2973                 int count = read(b, off + n, len - n);
2974                 if (count < 0) {
2975                     throw new EOFException();
2976                 }
2977                 n += count;
2978             }
2979         }
2980 
2981         public long skip(long n) throws IOException {
2982             if (n <= 0) {
2983                 return 0;
2984             }
2985             int skipped = 0;
2986             if (peekb >= 0) {
2987                 peekb = -1;
2988                 skipped++;
2989                 n--;
2990             }
2991             n = skipped + in.skip(n);
2992             totalBytesRead += n;
2993             return n;
2994         }
2995 
2996         public int available() throws IOException {
2997             return in.available() + ((peekb >= 0) ? 1 : 0);
2998         }
2999 
3000         public void close() throws IOException {
3001             in.close();
3002         }
3003 
3004         public long getBytesRead() {
3005             return totalBytesRead;
3006         }
3007     }
3008 
3009     private static final Unsafe UNSAFE = Unsafe.getUnsafe();
3010 
3011     /**
3012      * Performs a "freeze" action, required to adhere to final field semantics.
3013      *
3014      * <p> This method can be called unconditionally before returning the graph,
3015      * from the topmost readObject call, since it is expected that the
3016      * additional cost of the freeze action is negligible compared to
3017      * reconstituting even the most simple graph.
3018      *
3019      * <p> Nested calls to readObject do not issue freeze actions because the
3020      * sub-graph returned from a nested call is not guaranteed to be fully
3021      * initialized yet (possible cycles).
3022      */
3023     private void freeze() {
3024         // Issue a StoreStore|StoreLoad fence, which is at least sufficient
3025         // to provide final-freeze semantics.
3026         UNSAFE.storeFence();
3027     }
3028 
3029     /**
3030      * Input stream with two modes: in default mode, inputs data written in the
3031      * same format as DataOutputStream; in "block data" mode, inputs data
3032      * bracketed by block data markers (see object serialization specification
3033      * for details).  Buffering depends on block data mode: when in default
3034      * mode, no data is buffered in advance; when in block data mode, all data
3035      * for the current data block is read in at once (and buffered).
3036      */
3037     private class BlockDataInputStream
3038         extends InputStream implements DataInput
3039     {
3040         /** maximum data block length */
3041         private static final int MAX_BLOCK_SIZE = 1024;
3042         /** maximum data block header length */
3043         private static final int MAX_HEADER_SIZE = 5;
3044         /** (tunable) length of char buffer (for reading strings) */
3045         private static final int CHAR_BUF_SIZE = 256;
3046         /** readBlockHeader() return value indicating header read may block */
3047         private static final int HEADER_BLOCKED = -2;
3048         /** access to internal methods to count ASCII and inflate latin1/ASCII bytes to char */
3049         private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
3050 
3051         /** buffer for reading general/block data */
3052         private final byte[] buf = new byte[MAX_BLOCK_SIZE];
3053         /** buffer for reading block data headers */
3054         private final byte[] hbuf = new byte[MAX_HEADER_SIZE];
3055         /** char buffer for fast string reads */
3056         private final char[] cbuf = new char[CHAR_BUF_SIZE];
3057 
3058         /** block data mode */
3059         private boolean blkmode = false;
3060 
3061         // block data state fields; values meaningful only when blkmode true
3062         /** current offset into buf */
3063         private int pos = 0;
3064         /** end offset of valid data in buf, or -1 if no more block data */
3065         private int end = -1;
3066         /** number of bytes in current block yet to be read from stream */
3067         private int unread = 0;
3068 
3069         /** underlying stream (wrapped in peekable filter stream) */
3070         private final PeekInputStream in;
3071         /** loopback stream (for data reads that span data blocks) */
3072         private final DataInputStream din;
3073 
3074         /**
3075          * Creates new BlockDataInputStream on top of given underlying stream.
3076          * Block data mode is turned off by default.
3077          */
3078         BlockDataInputStream(InputStream in) {
3079             this.in = new PeekInputStream(in);
3080             din = new DataInputStream(this);
3081         }
3082 
3083         /**
3084          * Sets block data mode to the given mode (true == on, false == off)
3085          * and returns the previous mode value.  If the new mode is the same as
3086          * the old mode, no action is taken.  Throws IllegalStateException if
3087          * block data mode is being switched from on to off while unconsumed
3088          * block data is still present in the stream.
3089          */
3090         boolean setBlockDataMode(boolean newmode) throws IOException {
3091             if (blkmode == newmode) {
3092                 return blkmode;
3093             }
3094             if (newmode) {
3095                 pos = 0;
3096                 end = 0;
3097                 unread = 0;
3098             } else if (pos < end) {
3099                 throw new IllegalStateException("unread block data");
3100             }
3101             blkmode = newmode;
3102             return !blkmode;
3103         }
3104 
3105         /**
3106          * Returns true if the stream is currently in block data mode, false
3107          * otherwise.
3108          */
3109         boolean getBlockDataMode() {
3110             return blkmode;
3111         }
3112 
3113         /**
3114          * If in block data mode, skips to the end of the current group of data
3115          * blocks (but does not unset block data mode).  If not in block data
3116          * mode, throws an IllegalStateException.
3117          */
3118         void skipBlockData() throws IOException {
3119             if (!blkmode) {
3120                 throw new IllegalStateException("not in block data mode");
3121             }
3122             while (end >= 0) {
3123                 refill();
3124             }
3125         }
3126 
3127         /**
3128          * Attempts to read in the next block data header (if any).  If
3129          * canBlock is false and a full header cannot be read without possibly
3130          * blocking, returns HEADER_BLOCKED, else if the next element in the
3131          * stream is a block data header, returns the block data length
3132          * specified by the header, else returns -1.
3133          */
3134         private int readBlockHeader(boolean canBlock) throws IOException {
3135             if (defaultDataEnd) {
3136                 /*
3137                  * Fix for 4360508: stream is currently at the end of a field
3138                  * value block written via default serialization; since there
3139                  * is no terminating TC_ENDBLOCKDATA tag, simulate
3140                  * end-of-custom-data behavior explicitly.
3141                  */
3142                 return -1;
3143             }
3144             try {
3145                 for (;;) {
3146                     int avail = canBlock ? Integer.MAX_VALUE : in.available();
3147                     if (avail == 0) {
3148                         return HEADER_BLOCKED;
3149                     }
3150 
3151                     int tc = in.peek();
3152                     switch (tc) {
3153                         case TC_BLOCKDATA:
3154                             if (avail < 2) {
3155                                 return HEADER_BLOCKED;
3156                             }
3157                             in.readFully(hbuf, 0, 2);
3158                             return hbuf[1] & 0xFF;
3159 
3160                         case TC_BLOCKDATALONG:
3161                             if (avail < 5) {
3162                                 return HEADER_BLOCKED;
3163                             }
3164                             in.readFully(hbuf, 0, 5);
3165                             int len = ByteArray.getInt(hbuf, 1);
3166                             if (len < 0) {
3167                                 throw new StreamCorruptedException(
3168                                     "illegal block data header length: " +
3169                                     len);
3170                             }
3171                             return len;
3172 
3173                         /*
3174                          * TC_RESETs may occur in between data blocks.
3175                          * Unfortunately, this case must be parsed at a lower
3176                          * level than other typecodes, since primitive data
3177                          * reads may span data blocks separated by a TC_RESET.
3178                          */
3179                         case TC_RESET:
3180                             in.read();
3181                             handleReset();
3182                             break;
3183 
3184                         default:
3185                             if (tc >= 0 && (tc < TC_BASE || tc > TC_MAX)) {
3186                                 throw new StreamCorruptedException(
3187                                     String.format("invalid type code: %02X",
3188                                     tc));
3189                             }
3190                             return -1;
3191                     }
3192                 }
3193             } catch (EOFException ex) {
3194                 throw new StreamCorruptedException(
3195                     "unexpected EOF while reading block data header");
3196             }
3197         }
3198 
3199         /**
3200          * Refills internal buffer buf with block data.  Any data in buf at the
3201          * time of the call is considered consumed.  Sets the pos, end, and
3202          * unread fields to reflect the new amount of available block data; if
3203          * the next element in the stream is not a data block, sets pos and
3204          * unread to 0 and end to -1.
3205          */
3206         private void refill() throws IOException {
3207             try {
3208                 do {
3209                     pos = 0;
3210                     if (unread > 0) {
3211                         int n =
3212                             in.read(buf, 0, Math.min(unread, MAX_BLOCK_SIZE));
3213                         if (n >= 0) {
3214                             end = n;
3215                             unread -= n;
3216                         } else {
3217                             throw new StreamCorruptedException(
3218                                 "unexpected EOF in middle of data block");
3219                         }
3220                     } else {
3221                         int n = readBlockHeader(true);
3222                         if (n >= 0) {
3223                             end = 0;
3224                             unread = n;
3225                         } else {
3226                             end = -1;
3227                             unread = 0;
3228                         }
3229                     }
3230                 } while (pos == end);
3231             } catch (IOException ex) {
3232                 pos = 0;
3233                 end = -1;
3234                 unread = 0;
3235                 throw ex;
3236             }
3237         }
3238 
3239         /**
3240          * If in block data mode, returns the number of unconsumed bytes
3241          * remaining in the current data block.  If not in block data mode,
3242          * throws an IllegalStateException.
3243          */
3244         int currentBlockRemaining() {
3245             if (blkmode) {
3246                 return (end >= 0) ? (end - pos) + unread : 0;
3247             } else {
3248                 throw new IllegalStateException();
3249             }
3250         }
3251 
3252         /**
3253          * Peeks at (but does not consume) and returns the next byte value in
3254          * the stream, or -1 if the end of the stream/block data (if in block
3255          * data mode) has been reached.
3256          */
3257         int peek() throws IOException {
3258             if (blkmode) {
3259                 if (pos == end) {
3260                     refill();
3261                 }
3262                 return (end >= 0) ? (buf[pos] & 0xFF) : -1;
3263             } else {
3264                 return in.peek();
3265             }
3266         }
3267 
3268         /**
3269          * Peeks at (but does not consume) and returns the next byte value in
3270          * the stream, or throws EOFException if end of stream/block data has
3271          * been reached.
3272          */
3273         byte peekByte() throws IOException {
3274             int val = peek();
3275             if (val < 0) {
3276                 throw new EOFException();
3277             }
3278             return (byte) val;
3279         }
3280 
3281 
3282         /* ----------------- generic input stream methods ------------------ */
3283         /*
3284          * The following methods are equivalent to their counterparts in
3285          * InputStream, except that they interpret data block boundaries and
3286          * read the requested data from within data blocks when in block data
3287          * mode.
3288          */
3289 
3290         public int read() throws IOException {
3291             if (blkmode) {
3292                 if (pos == end) {
3293                     refill();
3294                 }
3295                 return (end >= 0) ? (buf[pos++] & 0xFF) : -1;
3296             } else {
3297                 return in.read();
3298             }
3299         }
3300 
3301         public int read(byte[] b, int off, int len) throws IOException {
3302             return read(b, off, len, false);
3303         }
3304 
3305         public long skip(long len) throws IOException {
3306             long remain = len;
3307             while (remain > 0) {
3308                 if (blkmode) {
3309                     if (pos == end) {
3310                         refill();
3311                     }
3312                     if (end < 0) {
3313                         break;
3314                     }
3315                     int nread = (int) Math.min(remain, end - pos);
3316                     remain -= nread;
3317                     pos += nread;
3318                 } else {
3319                     int nread = (int) Math.min(remain, MAX_BLOCK_SIZE);
3320                     if ((nread = in.read(buf, 0, nread)) < 0) {
3321                         break;
3322                     }
3323                     remain -= nread;
3324                 }
3325             }
3326             return len - remain;
3327         }
3328 
3329         public int available() throws IOException {
3330             if (blkmode) {
3331                 if ((pos == end) && (unread == 0)) {
3332                     int n;
3333                     while ((n = readBlockHeader(false)) == 0) ;
3334                     switch (n) {
3335                         case HEADER_BLOCKED:
3336                             break;
3337 
3338                         case -1:
3339                             pos = 0;
3340                             end = -1;
3341                             break;
3342 
3343                         default:
3344                             pos = 0;
3345                             end = 0;
3346                             unread = n;
3347                             break;
3348                     }
3349                 }
3350                 // avoid unnecessary call to in.available() if possible
3351                 int unreadAvail = (unread > 0) ?
3352                     Math.min(in.available(), unread) : 0;
3353                 return (end >= 0) ? (end - pos) + unreadAvail : 0;
3354             } else {
3355                 return in.available();
3356             }
3357         }
3358 
3359         public void close() throws IOException {
3360             if (blkmode) {
3361                 pos = 0;
3362                 end = -1;
3363                 unread = 0;
3364             }
3365             in.close();
3366         }
3367 
3368         /**
3369          * Attempts to read len bytes into byte array b at offset off.  Returns
3370          * the number of bytes read, or -1 if the end of stream/block data has
3371          * been reached.  If copy is true, reads values into an intermediate
3372          * buffer before copying them to b (to avoid exposing a reference to
3373          * b).
3374          */
3375         int read(byte[] b, int off, int len, boolean copy) throws IOException {
3376             if (len == 0) {
3377                 return 0;
3378             } else if (blkmode) {
3379                 if (pos == end) {
3380                     refill();
3381                 }
3382                 if (end < 0) {
3383                     return -1;
3384                 }
3385                 int nread = Math.min(len, end - pos);
3386                 System.arraycopy(buf, pos, b, off, nread);
3387                 pos += nread;
3388                 return nread;
3389             } else if (copy) {
3390                 int nread = in.read(buf, 0, Math.min(len, MAX_BLOCK_SIZE));
3391                 if (nread > 0) {
3392                     System.arraycopy(buf, 0, b, off, nread);
3393                 }
3394                 return nread;
3395             } else {
3396                 return in.read(b, off, len);
3397             }
3398         }
3399 
3400         /* ----------------- primitive data input methods ------------------ */
3401         /*
3402          * The following methods are equivalent to their counterparts in
3403          * DataInputStream, except that they interpret data block boundaries
3404          * and read the requested data from within data blocks when in block
3405          * data mode.
3406          */
3407 
3408         public void readFully(byte[] b) throws IOException {
3409             readFully(b, 0, b.length, false);
3410         }
3411 
3412         public void readFully(byte[] b, int off, int len) throws IOException {
3413             readFully(b, off, len, false);
3414         }
3415 
3416         public void readFully(byte[] b, int off, int len, boolean copy)
3417             throws IOException
3418         {
3419             while (len > 0) {
3420                 int n = read(b, off, len, copy);
3421                 if (n < 0) {
3422                     throw new EOFException();
3423                 }
3424                 off += n;
3425                 len -= n;
3426             }
3427         }
3428 
3429         public int skipBytes(int n) throws IOException {
3430             return din.skipBytes(n);
3431         }
3432 
3433         public boolean readBoolean() throws IOException {
3434             int v = read();
3435             if (v < 0) {
3436                 throw new EOFException();
3437             }
3438             return (v != 0);
3439         }
3440 
3441         public byte readByte() throws IOException {
3442             int v = read();
3443             if (v < 0) {
3444                 throw new EOFException();
3445             }
3446             return (byte) v;
3447         }
3448 
3449         public int readUnsignedByte() throws IOException {
3450             int v = read();
3451             if (v < 0) {
3452                 throw new EOFException();
3453             }
3454             return v;
3455         }
3456 
3457         public char readChar() throws IOException {
3458             if (!blkmode) {
3459                 pos = 0;
3460                 in.readFully(buf, 0, 2);
3461             } else if (end - pos < 2) {
3462                 return din.readChar();
3463             }
3464             char v = ByteArray.getChar(buf, pos);
3465             pos += 2;
3466             return v;
3467         }
3468 
3469         public short readShort() throws IOException {
3470             if (!blkmode) {
3471                 pos = 0;
3472                 in.readFully(buf, 0, 2);
3473             } else if (end - pos < 2) {
3474                 return din.readShort();
3475             }
3476             short v = ByteArray.getShort(buf, pos);
3477             pos += 2;
3478             return v;
3479         }
3480 
3481         public int readUnsignedShort() throws IOException {
3482             if (!blkmode) {
3483                 pos = 0;
3484                 in.readFully(buf, 0, 2);
3485             } else if (end - pos < 2) {
3486                 return din.readUnsignedShort();
3487             }
3488             int v = ByteArray.getShort(buf, pos) & 0xFFFF;
3489             pos += 2;
3490             return v;
3491         }
3492 
3493         public int readInt() throws IOException {
3494             if (!blkmode) {
3495                 pos = 0;
3496                 in.readFully(buf, 0, 4);
3497             } else if (end - pos < 4) {
3498                 return din.readInt();
3499             }
3500             int v = ByteArray.getInt(buf, pos);
3501             pos += 4;
3502             return v;
3503         }
3504 
3505         public float readFloat() throws IOException {
3506             if (!blkmode) {
3507                 pos = 0;
3508                 in.readFully(buf, 0, 4);
3509             } else if (end - pos < 4) {
3510                 return din.readFloat();
3511             }
3512             float v = ByteArray.getFloat(buf, pos);
3513             pos += 4;
3514             return v;
3515         }
3516 
3517         public long readLong() throws IOException {
3518             if (!blkmode) {
3519                 pos = 0;
3520                 in.readFully(buf, 0, 8);
3521             } else if (end - pos < 8) {
3522                 return din.readLong();
3523             }
3524             long v = ByteArray.getLong(buf, pos);
3525             pos += 8;
3526             return v;
3527         }
3528 
3529         public double readDouble() throws IOException {
3530             if (!blkmode) {
3531                 pos = 0;
3532                 in.readFully(buf, 0, 8);
3533             } else if (end - pos < 8) {
3534                 return din.readDouble();
3535             }
3536             double v = ByteArray.getDouble(buf, pos);
3537             pos += 8;
3538             return v;
3539         }
3540 
3541         public String readUTF() throws IOException {
3542             return readUTFBody(readUnsignedShort());
3543         }
3544 
3545         @SuppressWarnings("deprecation")
3546         public String readLine() throws IOException {
3547             return din.readLine();      // deprecated, not worth optimizing
3548         }
3549 
3550         /* -------------- primitive data array input methods --------------- */
3551         /*
3552          * The following methods read in spans of primitive data values.
3553          * Though equivalent to calling the corresponding primitive read
3554          * methods repeatedly, these methods are optimized for reading groups
3555          * of primitive data values more efficiently.
3556          */
3557 
3558         void readBooleans(boolean[] v, int off, int len) throws IOException {
3559             int stop, endoff = off + len;
3560             while (off < endoff) {
3561                 if (!blkmode) {
3562                     int span = Math.min(endoff - off, MAX_BLOCK_SIZE);
3563                     in.readFully(buf, 0, span);
3564                     stop = off + span;
3565                     pos = 0;
3566                 } else if (end - pos < 1) {
3567                     v[off++] = din.readBoolean();
3568                     continue;
3569                 } else {
3570                     stop = Math.min(endoff, off + end - pos);
3571                 }
3572 
3573                 while (off < stop) {
3574                     v[off++] = ByteArray.getBoolean(buf, pos++);
3575                 }
3576             }
3577         }
3578 
3579         void readChars(char[] v, int off, int len) throws IOException {
3580             int stop, endoff = off + len;
3581             while (off < endoff) {
3582                 if (!blkmode) {
3583                     int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 1);
3584                     in.readFully(buf, 0, span << 1);
3585                     stop = off + span;
3586                     pos = 0;
3587                 } else if (end - pos < 2) {
3588                     v[off++] = din.readChar();
3589                     continue;
3590                 } else {
3591                     stop = Math.min(endoff, off + ((end - pos) >> 1));
3592                 }
3593 
3594                 while (off < stop) {
3595                     v[off++] = ByteArray.getChar(buf, pos);
3596                     pos += 2;
3597                 }
3598             }
3599         }
3600 
3601         void readShorts(short[] v, int off, int len) throws IOException {
3602             int stop, endoff = off + len;
3603             while (off < endoff) {
3604                 if (!blkmode) {
3605                     int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 1);
3606                     in.readFully(buf, 0, span << 1);
3607                     stop = off + span;
3608                     pos = 0;
3609                 } else if (end - pos < 2) {
3610                     v[off++] = din.readShort();
3611                     continue;
3612                 } else {
3613                     stop = Math.min(endoff, off + ((end - pos) >> 1));
3614                 }
3615 
3616                 while (off < stop) {
3617                     v[off++] = ByteArray.getShort(buf, pos);
3618                     pos += 2;
3619                 }
3620             }
3621         }
3622 
3623         void readInts(int[] v, int off, int len) throws IOException {
3624             int stop, endoff = off + len;
3625             while (off < endoff) {
3626                 if (!blkmode) {
3627                     int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 2);
3628                     in.readFully(buf, 0, span << 2);
3629                     stop = off + span;
3630                     pos = 0;
3631                 } else if (end - pos < 4) {
3632                     v[off++] = din.readInt();
3633                     continue;
3634                 } else {
3635                     stop = Math.min(endoff, off + ((end - pos) >> 2));
3636                 }
3637 
3638                 while (off < stop) {
3639                     v[off++] = ByteArray.getInt(buf, pos);
3640                     pos += 4;
3641                 }
3642             }
3643         }
3644 
3645         void readFloats(float[] v, int off, int len) throws IOException {
3646             int stop, endoff = off + len;
3647             while (off < endoff) {
3648                 if (!blkmode) {
3649                     int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 2);
3650                     in.readFully(buf, 0, span << 2);
3651                     stop = off + span;
3652                     pos = 0;
3653                 } else if (end - pos < 4) {
3654                     v[off++] = din.readFloat();
3655                     continue;
3656                 } else {
3657                     stop = Math.min(endoff, ((end - pos) >> 2));
3658                 }
3659 
3660                 while (off < stop) {
3661                     v[off++] = ByteArray.getFloat(buf, pos);
3662                     pos += 4;
3663                 }
3664             }
3665         }
3666 
3667         void readLongs(long[] v, int off, int len) throws IOException {
3668             int stop, endoff = off + len;
3669             while (off < endoff) {
3670                 if (!blkmode) {
3671                     int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 3);
3672                     in.readFully(buf, 0, span << 3);
3673                     stop = off + span;
3674                     pos = 0;
3675                 } else if (end - pos < 8) {
3676                     v[off++] = din.readLong();
3677                     continue;
3678                 } else {
3679                     stop = Math.min(endoff, off + ((end - pos) >> 3));
3680                 }
3681 
3682                 while (off < stop) {
3683                     v[off++] = ByteArray.getLong(buf, pos);
3684                     pos += 8;
3685                 }
3686             }
3687         }
3688 
3689         void readDoubles(double[] v, int off, int len) throws IOException {
3690             int stop, endoff = off + len;
3691             while (off < endoff) {
3692                 if (!blkmode) {
3693                     int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 3);
3694                     in.readFully(buf, 0, span << 3);
3695                     stop = off + span;
3696                     pos = 0;
3697                 } else if (end - pos < 8) {
3698                     v[off++] = din.readDouble();
3699                     continue;
3700                 } else {
3701                     stop = Math.min(endoff - off, ((end - pos) >> 3));
3702                 }
3703 
3704                 while (off < stop) {
3705                     v[off++] = ByteArray.getDouble(buf, pos);
3706                     pos += 8;
3707                 }
3708             }
3709         }
3710 
3711         /**
3712          * Reads in string written in "long" UTF format.  "Long" UTF format is
3713          * identical to standard UTF, except that it uses an 8 byte header
3714          * (instead of the standard 2 bytes) to convey the UTF encoding length.
3715          */
3716         String readLongUTF() throws IOException {
3717             return readUTFBody(readLong());
3718         }
3719 
3720         /**
3721          * Reads in the "body" (i.e., the UTF representation minus the 2-byte
3722          * or 8-byte length header) of a UTF encoding, which occupies the next
3723          * utflen bytes.
3724          */
3725         private String readUTFBody(long utflen) throws IOException {
3726             if (!blkmode) {
3727                 end = pos = 0;
3728             }
3729 
3730             StringBuilder sbuf;
3731             if (utflen > 0 && utflen < Integer.MAX_VALUE) {
3732                 // Scan for leading ASCII chars
3733                 int avail = end - pos;
3734                 int ascii = JLA.countPositives(buf, pos, Math.min(avail, (int)utflen));
3735                 if (ascii == utflen) {
3736                     // Complete match, consume the buf[pos ... pos + ascii] range and return.
3737                     // Modified UTF-8 and ISO-8859-1 are both ASCII-compatible encodings bytes
3738                     // thus we can treat the range as ISO-8859-1 and avoid a redundant scan
3739                     // in the String constructor
3740                     String utf = new String(buf, pos, ascii, StandardCharsets.ISO_8859_1);
3741                     pos += ascii;
3742                     return utf;
3743                 }
3744                 // Avoid allocating a StringBuilder if there's enough data in buf and
3745                 // cbuf is large enough
3746                 if (avail >= utflen && utflen <= CHAR_BUF_SIZE) {
3747                     JLA.inflateBytesToChars(buf, pos, cbuf, 0, ascii);
3748                     pos += ascii;
3749                     int cbufPos = readUTFSpan(ascii, utflen - ascii);
3750                     return new String(cbuf, 0, cbufPos);
3751                 }
3752                 // a reasonable initial capacity based on the UTF length
3753                 int initialCapacity = Math.min((int)utflen, 0xFFFF);
3754                 sbuf = new StringBuilder(initialCapacity);
3755             } else {
3756                 sbuf = new StringBuilder();
3757             }
3758 
3759             while (utflen > 0) {
3760                 int avail = end - pos;
3761                 if (avail >= 3 || (long) avail == utflen) {
3762                     int cbufPos = readUTFSpan(0, utflen);
3763                     // pos has advanced: adjust utflen by the difference in
3764                     // available bytes
3765                     utflen -= avail - (end - pos);
3766                     sbuf.append(cbuf, 0, cbufPos);
3767                 } else {
3768                     if (blkmode) {
3769                         // near block boundary, read one byte at a time
3770                         utflen -= readUTFChar(sbuf, utflen);
3771                     } else {
3772                         // shift and refill buffer manually
3773                         if (avail > 0) {
3774                             System.arraycopy(buf, pos, buf, 0, avail);
3775                         }
3776                         pos = 0;
3777                         end = (int) Math.min(MAX_BLOCK_SIZE, utflen);
3778                         in.readFully(buf, avail, end - avail);
3779                     }
3780                 }
3781             }
3782 
3783             return sbuf.toString();
3784         }
3785 
3786         /**
3787          * Reads span of UTF-encoded characters out of internal buffer
3788          * (starting at offset pos), consuming no more than utflen bytes.
3789          * Appends read characters to cbuf. Returns the current position
3790          * in cbuf.
3791          */
3792         private int readUTFSpan(int cpos, long utflen)
3793             throws IOException
3794         {
3795             int start = pos;
3796             int avail = Math.min(end - pos, CHAR_BUF_SIZE);
3797             // stop short of last char unless all of utf bytes in buffer
3798             int stop = start + ((utflen > avail) ? avail - 2 : (int) utflen);
3799             boolean outOfBounds = false;
3800 
3801             try {
3802                 while (pos < stop) {
3803                     int b1, b2, b3;
3804                     b1 = buf[pos++] & 0xFF;
3805                     switch (b1 >> 4) {
3806                         case 0, 1, 2, 3, 4, 5, 6, 7 -> // 1 byte format: 0xxxxxxx
3807                             cbuf[cpos++] = (char) b1;
3808                         case 12, 13 -> {  // 2 byte format: 110xxxxx 10xxxxxx
3809                             b2 = buf[pos++];
3810                             if ((b2 & 0xC0) != 0x80) {
3811                                 throw new UTFDataFormatException();
3812                             }
3813                             cbuf[cpos++] = (char) (((b1 & 0x1F) << 6) |
3814                                                    ((b2 & 0x3F) << 0));
3815                         }
3816                         case 14 -> {  // 3 byte format: 1110xxxx 10xxxxxx 10xxxxxx
3817                             b3 = buf[pos + 1];
3818                             b2 = buf[pos + 0];
3819                             pos += 2;
3820                             if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) {
3821                                 throw new UTFDataFormatException();
3822                             }
3823                             cbuf[cpos++] = (char) (((b1 & 0x0F) << 12) |
3824                                                    ((b2 & 0x3F) << 6) |
3825                                                    ((b3 & 0x3F) << 0));
3826                         }
3827                         default ->  throw new UTFDataFormatException(); // 10xx xxxx, 1111 xxxx
3828                     }
3829                 }
3830             } catch (ArrayIndexOutOfBoundsException ex) {
3831                 outOfBounds = true;
3832             } finally {
3833                 if (outOfBounds || (pos - start) > utflen) {
3834                     /*
3835                      * Fix for 4450867: if a malformed utf char causes the
3836                      * conversion loop to scan past the expected end of the utf
3837                      * string, only consume the expected number of utf bytes.
3838                      */
3839                     pos = start + (int) utflen;
3840                     throw new UTFDataFormatException();
3841                 }
3842             }
3843             return cpos;
3844         }
3845 
3846         /**
3847          * Reads in single UTF-encoded character one byte at a time, appends
3848          * the character to sbuf, and returns the number of bytes consumed.
3849          * This method is used when reading in UTF strings written in block
3850          * data mode to handle UTF-encoded characters which (potentially)
3851          * straddle block-data boundaries.
3852          */
3853         private int readUTFChar(StringBuilder sbuf, long utflen)
3854             throws IOException
3855         {
3856             int b1, b2, b3;
3857             b1 = readByte() & 0xFF;
3858             switch (b1 >> 4) {
3859                 case 0, 1, 2, 3, 4, 5, 6, 7 -> {     // 1 byte format: 0xxxxxxx
3860                     sbuf.append((char) b1);
3861                     return 1;
3862                 }
3863                 case 12, 13 -> {    // 2 byte format: 110xxxxx 10xxxxxx
3864                     if (utflen < 2) {
3865                         throw new UTFDataFormatException();
3866                     }
3867                     b2 = readByte();
3868                     if ((b2 & 0xC0) != 0x80) {
3869                         throw new UTFDataFormatException();
3870                     }
3871                     sbuf.append((char) (((b1 & 0x1F) << 6) |
3872                                         ((b2 & 0x3F) << 0)));
3873                     return 2;
3874                 }
3875                 case 14 -> {    // 3 byte format: 1110xxxx 10xxxxxx 10xxxxxx
3876                     if (utflen < 3) {
3877                         if (utflen == 2) {
3878                             readByte();         // consume remaining byte
3879                         }
3880                         throw new UTFDataFormatException();
3881                     }
3882                     b2 = readByte();
3883                     b3 = readByte();
3884                     if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) {
3885                         throw new UTFDataFormatException();
3886                     }
3887                     sbuf.append((char) (((b1 & 0x0F) << 12) |
3888                                         ((b2 & 0x3F) << 6)  |
3889                                         ((b3 & 0x3F) << 0)));
3890                     return 3;
3891                 }
3892                 default -> throw new UTFDataFormatException(); // 10xx xxxx, 1111 xxxx
3893             }
3894         }
3895 
3896         /**
3897          * {@return the number of bytes read from the input stream}
3898          */
3899         long getBytesRead() {
3900             return in.getBytesRead();
3901         }
3902     }
3903 
3904     /**
3905      * Unsynchronized table which tracks wire handle to object mappings, as
3906      * well as ClassNotFoundExceptions associated with deserialized objects.
3907      * This class implements an exception-propagation algorithm for
3908      * determining which objects should have ClassNotFoundExceptions associated
3909      * with them, taking into account cycles and discontinuities (e.g., skipped
3910      * fields) in the object graph.
3911      *
3912      * <p>General use of the table is as follows: during deserialization, a
3913      * given object is first assigned a handle by calling the assign method.
3914      * This method leaves the assigned handle in an "open" state, wherein
3915      * dependencies on the exception status of other handles can be registered
3916      * by calling the markDependency method, or an exception can be directly
3917      * associated with the handle by calling markException.  When a handle is
3918      * tagged with an exception, the HandleTable assumes responsibility for
3919      * propagating the exception to any other objects which depend
3920      * (transitively) on the exception-tagged object.
3921      *
3922      * <p>Once all exception information/dependencies for the handle have been
3923      * registered, the handle should be "closed" by calling the finish method
3924      * on it.  The act of finishing a handle allows the exception propagation
3925      * algorithm to aggressively prune dependency links, lessening the
3926      * performance/memory impact of exception tracking.
3927      *
3928      * <p>Note that the exception propagation algorithm used depends on handles
3929      * being assigned/finished in LIFO order; however, for simplicity as well
3930      * as memory conservation, it does not enforce this constraint.
3931      */
3932     // REMIND: add full description of exception propagation algorithm?
3933     private static final class HandleTable {
3934 
3935         /* status codes indicating whether object has associated exception */
3936         private static final byte STATUS_OK = 1;
3937         private static final byte STATUS_UNKNOWN = 2;
3938         private static final byte STATUS_EXCEPTION = 3;
3939 
3940         /** array mapping handle -> object status */
3941         byte[] status;
3942         /** array mapping handle -> object/exception (depending on status) */
3943         Object[] entries;
3944         /** array mapping handle -> list of dependent handles (if any) */
3945         HandleList[] deps;
3946         /** lowest unresolved dependency */
3947         int lowDep = -1;
3948         /** number of handles in table */
3949         int size = 0;
3950 
3951         /**
3952          * Creates handle table with the given initial capacity.
3953          */
3954         HandleTable(int initialCapacity) {
3955             status = new byte[initialCapacity];
3956             entries = new Object[initialCapacity];
3957             deps = new HandleList[initialCapacity];
3958         }
3959 
3960         /**
3961          * Assigns next available handle to given object, and returns assigned
3962          * handle.  Once object has been completely deserialized (and all
3963          * dependencies on other objects identified), the handle should be
3964          * "closed" by passing it to finish().
3965          */
3966         int assign(Object obj) {
3967             if (size >= entries.length) {
3968                 grow();
3969             }
3970             status[size] = STATUS_UNKNOWN;
3971             entries[size] = obj;
3972             return size++;
3973         }
3974 
3975         /**
3976          * Registers a dependency (in exception status) of one handle on
3977          * another.  The dependent handle must be "open" (i.e., assigned, but
3978          * not finished yet).  No action is taken if either dependent or target
3979          * handle is NULL_HANDLE. Additionally, no action is taken if the
3980          * dependent and target are the same.
3981          */
3982         void markDependency(int dependent, int target) {
3983             if (dependent == target || dependent == NULL_HANDLE || target == NULL_HANDLE) {
3984                 return;
3985             }
3986             switch (status[dependent]) {
3987 
3988                 case STATUS_UNKNOWN:
3989                     switch (status[target]) {
3990                         case STATUS_OK:
3991                             // ignore dependencies on objs with no exception
3992                             break;
3993 
3994                         case STATUS_EXCEPTION:
3995                             // eagerly propagate exception
3996                             markException(dependent,
3997                                 (ClassNotFoundException) entries[target]);
3998                             break;
3999 
4000                         case STATUS_UNKNOWN:
4001                             // add to dependency list of target
4002                             if (deps[target] == null) {
4003                                 deps[target] = new HandleList();
4004                             }
4005                             deps[target].add(dependent);
4006 
4007                             // remember lowest unresolved target seen
4008                             if (lowDep < 0 || lowDep > target) {
4009                                 lowDep = target;
4010                             }
4011                             break;
4012 
4013                         default:
4014                             throw new InternalError();
4015                     }
4016                     break;
4017 
4018                 case STATUS_EXCEPTION:
4019                     break;
4020 
4021                 default:
4022                     throw new InternalError();
4023             }
4024         }
4025 
4026         /**
4027          * Associates a ClassNotFoundException (if one not already associated)
4028          * with the currently active handle and propagates it to other
4029          * referencing objects as appropriate.  The specified handle must be
4030          * "open" (i.e., assigned, but not finished yet).
4031          */
4032         void markException(int handle, ClassNotFoundException ex) {
4033             switch (status[handle]) {
4034                 case STATUS_UNKNOWN:
4035                     status[handle] = STATUS_EXCEPTION;
4036                     entries[handle] = ex;
4037 
4038                     // propagate exception to dependents
4039                     HandleList dlist = deps[handle];
4040                     if (dlist != null) {
4041                         int ndeps = dlist.size();
4042                         for (int i = 0; i < ndeps; i++) {
4043                             markException(dlist.get(i), ex);
4044                         }
4045                         deps[handle] = null;
4046                     }
4047                     break;
4048 
4049                 case STATUS_EXCEPTION:
4050                     break;
4051 
4052                 default:
4053                     throw new InternalError();
4054             }
4055         }
4056 
4057         /**
4058          * Marks given handle as finished, meaning that no new dependencies
4059          * will be marked for handle.  Calls to the assign and finish methods
4060          * must occur in LIFO order.
4061          */
4062         void finish(int handle) {
4063             int end;
4064             if (lowDep < 0) {
4065                 // no pending unknowns, only resolve current handle
4066                 end = handle + 1;
4067             } else if (lowDep >= handle) {
4068                 // pending unknowns now clearable, resolve all upward handles
4069                 end = size;
4070                 lowDep = -1;
4071             } else {
4072                 // unresolved backrefs present, can't resolve anything yet
4073                 return;
4074             }
4075 
4076             // change STATUS_UNKNOWN -> STATUS_OK in selected span of handles
4077             for (int i = handle; i < end; i++) {
4078                 switch (status[i]) {
4079                     case STATUS_UNKNOWN:
4080                         status[i] = STATUS_OK;
4081                         deps[i] = null;
4082                         break;
4083 
4084                     case STATUS_OK:
4085                     case STATUS_EXCEPTION:
4086                         break;
4087 
4088                     default:
4089                         throw new InternalError();
4090                 }
4091             }
4092         }
4093 
4094         /**
4095          * Assigns a new object to the given handle.  The object previously
4096          * associated with the handle is forgotten.  This method has no effect
4097          * if the given handle already has an exception associated with it.
4098          * This method may be called at any time after the handle is assigned.
4099          */
4100         void setObject(int handle, Object obj) {
4101             switch (status[handle]) {
4102                 case STATUS_UNKNOWN:
4103                 case STATUS_OK:
4104                     entries[handle] = obj;
4105                     break;
4106 
4107                 case STATUS_EXCEPTION:
4108                     break;
4109 
4110                 default:
4111                     throw new InternalError();
4112             }
4113         }
4114 
4115         /**
4116          * Looks up and returns object associated with the given handle.
4117          * Returns null if the given handle is NULL_HANDLE, or if it has an
4118          * associated ClassNotFoundException.
4119          */
4120         Object lookupObject(int handle) {
4121             return (handle != NULL_HANDLE &&
4122                     status[handle] != STATUS_EXCEPTION) ?
4123                 entries[handle] : null;
4124         }
4125 
4126         /**
4127          * Looks up and returns ClassNotFoundException associated with the
4128          * given handle.  Returns null if the given handle is NULL_HANDLE, or
4129          * if there is no ClassNotFoundException associated with the handle.
4130          */
4131         ClassNotFoundException lookupException(int handle) {
4132             return (handle != NULL_HANDLE &&
4133                     status[handle] == STATUS_EXCEPTION) ?
4134                 (ClassNotFoundException) entries[handle] : null;
4135         }
4136 
4137         /**
4138          * Resets table to its initial state.
4139          */
4140         void clear() {
4141             Arrays.fill(status, 0, size, (byte) 0);
4142             Arrays.fill(entries, 0, size, null);
4143             Arrays.fill(deps, 0, size, null);
4144             lowDep = -1;
4145             size = 0;
4146         }
4147 
4148         /**
4149          * Returns number of handles registered in table.
4150          */
4151         int size() {
4152             return size;
4153         }
4154 
4155         /**
4156          * Expands capacity of internal arrays.
4157          */
4158         private void grow() {
4159             int newCapacity = (entries.length << 1) + 1;
4160 
4161             byte[] newStatus = new byte[newCapacity];
4162             Object[] newEntries = new Object[newCapacity];
4163             HandleList[] newDeps = new HandleList[newCapacity];
4164 
4165             System.arraycopy(status, 0, newStatus, 0, size);
4166             System.arraycopy(entries, 0, newEntries, 0, size);
4167             System.arraycopy(deps, 0, newDeps, 0, size);
4168 
4169             status = newStatus;
4170             entries = newEntries;
4171             deps = newDeps;
4172         }
4173 
4174         /**
4175          * Simple growable list of (integer) handles.
4176          */
4177         private static class HandleList {
4178             private int[] list = new int[4];
4179             private int size = 0;
4180 
4181             public HandleList() {
4182             }
4183 
4184             public void add(int handle) {
4185                 if (size >= list.length) {
4186                     int[] newList = new int[list.length << 1];
4187                     System.arraycopy(list, 0, newList, 0, list.length);
4188                     list = newList;
4189                 }
4190                 list[size++] = handle;
4191             }
4192 
4193             public int get(int index) {
4194                 if (index >= size) {
4195                     throw new ArrayIndexOutOfBoundsException();
4196                 }
4197                 return list[index];
4198             }
4199 
4200             public int size() {
4201                 return size;
4202             }
4203         }
4204     }
4205 
4206     /**
4207      * Method for cloning arrays in case of using unsharing reading
4208      */
4209     private static Object cloneArray(Object array) {
4210         if (array instanceof Object[]) {
4211             return ((Object[]) array).clone();
4212         } else if (array instanceof boolean[]) {
4213             return ((boolean[]) array).clone();
4214         } else if (array instanceof byte[]) {
4215             return ((byte[]) array).clone();
4216         } else if (array instanceof char[]) {
4217             return ((char[]) array).clone();
4218         } else if (array instanceof double[]) {
4219             return ((double[]) array).clone();
4220         } else if (array instanceof float[]) {
4221             return ((float[]) array).clone();
4222         } else if (array instanceof int[]) {
4223             return ((int[]) array).clone();
4224         } else if (array instanceof long[]) {
4225             return ((long[]) array).clone();
4226         } else if (array instanceof short[]) {
4227             return ((short[]) array).clone();
4228         } else {
4229             throw new AssertionError();
4230         }
4231     }
4232 
4233     static {
4234         SharedSecrets.setJavaObjectInputStreamAccess(ObjectInputStream::checkArray);
4235         SharedSecrets.setJavaObjectInputStreamReadString(ObjectInputStream::readString);
4236     }
4237 
4238 }