Home | History | Annotate | Download | only in io
      1 /*
      2  *  Licensed to the Apache Software Foundation (ASF) under one or more
      3  *  contributor license agreements.  See the NOTICE file distributed with
      4  *  this work for additional information regarding copyright ownership.
      5  *  The ASF licenses this file to You under the Apache License, Version 2.0
      6  *  (the "License"); you may not use this file except in compliance with
      7  *  the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  */
     17 
     18 package java.io;
     19 
     20 import dalvik.system.VMStack;
     21 import java.io.EmulatedFields.ObjectSlot;
     22 import java.lang.reflect.Array;
     23 import java.lang.reflect.Field;
     24 import java.lang.reflect.InvocationTargetException;
     25 import java.lang.reflect.Method;
     26 import java.lang.reflect.Modifier;
     27 import java.lang.reflect.Proxy;
     28 import java.util.ArrayList;
     29 import java.util.Arrays;
     30 import java.util.HashMap;
     31 import java.util.List;
     32 import libcore.util.EmptyArray;
     33 
     34 /**
     35  * A specialized {@link InputStream} that is able to read (deserialize) Java
     36  * objects as well as primitive data types (int, byte, char etc.). The data has
     37  * typically been saved using an ObjectOutputStream.
     38  *
     39  * @see ObjectOutputStream
     40  * @see ObjectInput
     41  * @see Serializable
     42  * @see Externalizable
     43  */
     44 public class ObjectInputStream extends InputStream implements ObjectInput, ObjectStreamConstants {
     45 
     46     // TODO: this is non-static to avoid sync contention. Would static be faster?
     47     private InputStream emptyStream = new ByteArrayInputStream(EmptyArray.BYTE);
     48 
     49     // To put into objectsRead when reading unsharedObject
     50     private static final Object UNSHARED_OBJ = new Object(); // $NON-LOCK-1$
     51 
     52     // If the receiver has already read & not consumed a TC code
     53     private boolean hasPushbackTC;
     54 
     55     // Push back TC code if the variable above is true
     56     private byte pushbackTC;
     57 
     58     // How many nested levels to readObject. When we reach 0 we have to validate
     59     // the graph then reset it
     60     private int nestedLevels;
     61 
     62     // All objects are assigned an ID (integer handle)
     63     private int nextHandle;
     64 
     65     // Where we read from
     66     private DataInputStream input;
     67 
     68     // Where we read primitive types from
     69     private DataInputStream primitiveTypes;
     70 
     71     // Where we keep primitive type data
     72     private InputStream primitiveData = emptyStream;
     73 
     74     // Resolve object is a mechanism for replacement
     75     private boolean enableResolve;
     76 
     77     /**
     78      * All the objects we've read, indexed by their serialization handle (minus the base offset).
     79      */
     80     private ArrayList<Object> objectsRead;
     81 
     82     // Used by defaultReadObject
     83     private Object currentObject;
     84 
     85     // Used by defaultReadObject
     86     private ObjectStreamClass currentClass;
     87 
     88     // All validations to be executed when the complete graph is read. See inner
     89     // type below.
     90     private InputValidationDesc[] validations;
     91 
     92     // Allows the receiver to decide if it needs to call readObjectOverride
     93     private boolean subclassOverridingImplementation;
     94 
     95     // Original caller's class loader, used to perform class lookups
     96     private ClassLoader callerClassLoader;
     97 
     98     // false when reading missing fields
     99     private boolean mustResolve = true;
    100 
    101     // Handle for the current class descriptor
    102     private int descriptorHandle = -1;
    103 
    104     private static final HashMap<String, Class<?>> PRIMITIVE_CLASSES = new HashMap<String, Class<?>>();
    105     static {
    106         PRIMITIVE_CLASSES.put("boolean", boolean.class);
    107         PRIMITIVE_CLASSES.put("byte", byte.class);
    108         PRIMITIVE_CLASSES.put("char", char.class);
    109         PRIMITIVE_CLASSES.put("double", double.class);
    110         PRIMITIVE_CLASSES.put("float", float.class);
    111         PRIMITIVE_CLASSES.put("int", int.class);
    112         PRIMITIVE_CLASSES.put("long", long.class);
    113         PRIMITIVE_CLASSES.put("short", short.class);
    114         PRIMITIVE_CLASSES.put("void", void.class);
    115     }
    116 
    117     // Internal type used to keep track of validators & corresponding priority
    118     static class InputValidationDesc {
    119         ObjectInputValidation validator;
    120 
    121         int priority;
    122     }
    123 
    124     /**
    125      * GetField is an inner class that provides access to the persistent fields
    126      * read from the source stream.
    127      */
    128     public abstract static class GetField {
    129         /**
    130          * Gets the ObjectStreamClass that describes a field.
    131          *
    132          * @return the descriptor class for a serialized field.
    133          */
    134         public abstract ObjectStreamClass getObjectStreamClass();
    135 
    136         /**
    137          * Indicates if the field identified by {@code name} is defaulted. This
    138          * means that it has no value in this stream.
    139          *
    140          * @param name
    141          *            the name of the field to check.
    142          * @return {@code true} if the field is defaulted, {@code false}
    143          *         otherwise.
    144          * @throws IllegalArgumentException
    145          *             if {@code name} does not identify a serializable field.
    146          * @throws IOException
    147          *             if an error occurs while reading from the source input
    148          *             stream.
    149          */
    150         public abstract boolean defaulted(String name) throws IOException,
    151                 IllegalArgumentException;
    152 
    153         /**
    154          * Gets the value of the boolean field identified by {@code name} from
    155          * the persistent field.
    156          *
    157          * @param name
    158          *            the name of the field to get.
    159          * @param defaultValue
    160          *            the default value that is used if the field does not have
    161          *            a value when read from the source stream.
    162          * @return the value of the field identified by {@code name}.
    163          * @throws IOException
    164          *             if an error occurs while reading from the source input
    165          *             stream.
    166          * @throws IllegalArgumentException
    167          *             if the type of the field identified by {@code name} is
    168          *             not {@code boolean}.
    169          */
    170         public abstract boolean get(String name, boolean defaultValue)
    171                 throws IOException, IllegalArgumentException;
    172 
    173         /**
    174          * Gets the value of the character field identified by {@code name} from
    175          * the persistent field.
    176          *
    177          * @param name
    178          *            the name of the field to get.
    179          * @param defaultValue
    180          *            the default value that is used if the field does not have
    181          *            a value when read from the source stream.
    182          * @return the value of the field identified by {@code name}.
    183          * @throws IOException
    184          *             if an error occurs while reading from the source input
    185          *             stream.
    186          * @throws IllegalArgumentException
    187          *             if the type of the field identified by {@code name} is
    188          *             not {@code char}.
    189          */
    190         public abstract char get(String name, char defaultValue)
    191                 throws IOException, IllegalArgumentException;
    192 
    193         /**
    194          * Gets the value of the byte field identified by {@code name} from the
    195          * persistent field.
    196          *
    197          * @param name
    198          *            the name of the field to get.
    199          * @param defaultValue
    200          *            the default value that is used if the field does not have
    201          *            a value when read from the source stream.
    202          * @return the value of the field identified by {@code name}.
    203          * @throws IOException
    204          *             if an error occurs while reading from the source input
    205          *             stream.
    206          * @throws IllegalArgumentException
    207          *             if the type of the field identified by {@code name} is
    208          *             not {@code byte}.
    209          */
    210         public abstract byte get(String name, byte defaultValue)
    211                 throws IOException, IllegalArgumentException;
    212 
    213         /**
    214          * Gets the value of the short field identified by {@code name} from the
    215          * persistent field.
    216          *
    217          * @param name
    218          *            the name of the field to get.
    219          * @param defaultValue
    220          *            the default value that is used if the field does not have
    221          *            a value when read from the source stream.
    222          * @return the value of the field identified by {@code name}.
    223          * @throws IOException
    224          *             if an error occurs while reading from the source input
    225          *             stream.
    226          * @throws IllegalArgumentException
    227          *             if the type of the field identified by {@code name} is
    228          *             not {@code short}.
    229          */
    230         public abstract short get(String name, short defaultValue)
    231                 throws IOException, IllegalArgumentException;
    232 
    233         /**
    234          * Gets the value of the integer field identified by {@code name} from
    235          * the persistent field.
    236          *
    237          * @param name
    238          *            the name of the field to get.
    239          * @param defaultValue
    240          *            the default value that is used if the field does not have
    241          *            a value when read from the source stream.
    242          * @return the value of the field identified by {@code name}.
    243          * @throws IOException
    244          *             if an error occurs while reading from the source input
    245          *             stream.
    246          * @throws IllegalArgumentException
    247          *             if the type of the field identified by {@code name} is
    248          *             not {@code int}.
    249          */
    250         public abstract int get(String name, int defaultValue)
    251                 throws IOException, IllegalArgumentException;
    252 
    253         /**
    254          * Gets the value of the long field identified by {@code name} from the
    255          * persistent field.
    256          *
    257          * @param name
    258          *            the name of the field to get.
    259          * @param defaultValue
    260          *            the default value that is used if the field does not have
    261          *            a value when read from the source stream.
    262          * @return the value of the field identified by {@code name}.
    263          * @throws IOException
    264          *             if an error occurs while reading from the source input
    265          *             stream.
    266          * @throws IllegalArgumentException
    267          *             if the type of the field identified by {@code name} is
    268          *             not {@code long}.
    269          */
    270         public abstract long get(String name, long defaultValue)
    271                 throws IOException, IllegalArgumentException;
    272 
    273         /**
    274          * Gets the value of the float field identified by {@code name} from the
    275          * persistent field.
    276          *
    277          * @param name
    278          *            the name of the field to get.
    279          * @param defaultValue
    280          *            the default value that is used if the field does not have
    281          *            a value when read from the source stream.
    282          * @return the value of the field identified by {@code name}.
    283          * @throws IOException
    284          *             if an error occurs while reading from the source input
    285          *             stream.
    286          * @throws IllegalArgumentException
    287          *             if the type of the field identified by {@code float} is
    288          *             not {@code char}.
    289          */
    290         public abstract float get(String name, float defaultValue)
    291                 throws IOException, IllegalArgumentException;
    292 
    293         /**
    294          * Gets the value of the double field identified by {@code name} from
    295          * the persistent field.
    296          *
    297          * @param name
    298          *            the name of the field to get.
    299          * @param defaultValue
    300          *            the default value that is used if the field does not have
    301          *            a value when read from the source stream.
    302          * @return the value of the field identified by {@code name}.
    303          * @throws IOException
    304          *             if an error occurs while reading from the source input
    305          *             stream.
    306          * @throws IllegalArgumentException
    307          *             if the type of the field identified by {@code name} is
    308          *             not {@code double}.
    309          */
    310         public abstract double get(String name, double defaultValue)
    311                 throws IOException, IllegalArgumentException;
    312 
    313         /**
    314          * Gets the value of the object field identified by {@code name} from
    315          * the persistent field.
    316          *
    317          * @param name
    318          *            the name of the field to get.
    319          * @param defaultValue
    320          *            the default value that is used if the field does not have
    321          *            a value when read from the source stream.
    322          * @return the value of the field identified by {@code name}.
    323          * @throws IOException
    324          *             if an error occurs while reading from the source input
    325          *             stream.
    326          * @throws IllegalArgumentException
    327          *             if the type of the field identified by {@code name} is
    328          *             not {@code Object}.
    329          */
    330         public abstract Object get(String name, Object defaultValue)
    331                 throws IOException, IllegalArgumentException;
    332     }
    333 
    334     /**
    335      * Constructs a new ObjectInputStream. This default constructor can be used
    336      * by subclasses that do not want to use the public constructor if it
    337      * allocates unneeded data.
    338      *
    339      * @throws IOException
    340      *             if an error occurs when creating this stream.
    341      */
    342     protected ObjectInputStream() throws IOException {
    343         // WARNING - we should throw IOException if not called from a subclass
    344         // according to the JavaDoc. Add the test.
    345         this.subclassOverridingImplementation = true;
    346     }
    347 
    348     /**
    349      * Constructs a new ObjectInputStream that reads from the InputStream
    350      * {@code input}.
    351      *
    352      * @param input
    353      *            the non-null source InputStream to filter reads on.
    354      * @throws IOException
    355      *             if an error occurs while reading the stream header.
    356      * @throws StreamCorruptedException
    357      *             if the source stream does not contain serialized objects that
    358      *             can be read.
    359      */
    360     public ObjectInputStream(InputStream input) throws StreamCorruptedException, IOException {
    361         this.input = (input instanceof DataInputStream)
    362                 ? (DataInputStream) input : new DataInputStream(input);
    363         primitiveTypes = new DataInputStream(this);
    364         enableResolve = false;
    365         this.subclassOverridingImplementation = false;
    366         resetState();
    367         nestedLevels = 0;
    368         // So read...() methods can be used by
    369         // subclasses during readStreamHeader()
    370         primitiveData = this.input;
    371         // Has to be done here according to the specification
    372         readStreamHeader();
    373         primitiveData = emptyStream;
    374     }
    375 
    376     @Override
    377     public int available() throws IOException {
    378         // returns 0 if next data is an object, or N if reading primitive types
    379         checkReadPrimitiveTypes();
    380         return primitiveData.available();
    381     }
    382 
    383     /**
    384      * Checks to if it is ok to read primitive types from this stream at
    385      * this point. One is not supposed to read primitive types when about to
    386      * read an object, for example, so an exception has to be thrown.
    387      *
    388      * @throws IOException
    389      *             If any IO problem occurred when trying to read primitive type
    390      *             or if it is illegal to read primitive types
    391      */
    392     private void checkReadPrimitiveTypes() throws IOException {
    393         // If we still have primitive data, it is ok to read primitive data
    394         if (primitiveData == input || primitiveData.available() > 0) {
    395             return;
    396         }
    397 
    398         // If we got here either we had no Stream previously created or
    399         // we no longer have data in that one, so get more bytes
    400         do {
    401             int next = 0;
    402             if (hasPushbackTC) {
    403                 hasPushbackTC = false;
    404             } else {
    405                 next = input.read();
    406                 pushbackTC = (byte) next;
    407             }
    408             switch (pushbackTC) {
    409                 case TC_BLOCKDATA:
    410                     primitiveData = new ByteArrayInputStream(readBlockData());
    411                     return;
    412                 case TC_BLOCKDATALONG:
    413                     primitiveData = new ByteArrayInputStream(readBlockDataLong());
    414                     return;
    415                 case TC_RESET:
    416                     resetState();
    417                     break;
    418                 default:
    419                     if (next != -1) {
    420                         pushbackTC();
    421                     }
    422                     return;
    423             }
    424             // Only TC_RESET falls through
    425         } while (true);
    426     }
    427 
    428     /**
    429      * Closes this stream. This implementation closes the source stream.
    430      *
    431      * @throws IOException
    432      *             if an error occurs while closing this stream.
    433      */
    434     @Override
    435     public void close() throws IOException {
    436         input.close();
    437     }
    438 
    439     /**
    440      * Default method to read objects from this stream. Serializable fields
    441      * defined in the object's class and superclasses are read from the source
    442      * stream.
    443      *
    444      * @throws ClassNotFoundException
    445      *             if the object's class cannot be found.
    446      * @throws IOException
    447      *             if an I/O error occurs while reading the object data.
    448      * @throws NotActiveException
    449      *             if this method is not called from {@code readObject()}.
    450      * @see ObjectOutputStream#defaultWriteObject
    451      */
    452     public void defaultReadObject() throws IOException, ClassNotFoundException,
    453             NotActiveException {
    454         if (currentObject != null || !mustResolve) {
    455             readFieldValues(currentObject, currentClass);
    456         } else {
    457             throw new NotActiveException();
    458         }
    459     }
    460 
    461     /**
    462      * Enables object replacement for this stream. By default this is not
    463      * enabled. Only trusted subclasses (loaded with system class loader) are
    464      * allowed to change this status.
    465      *
    466      * @param enable
    467      *            {@code true} to enable object replacement; {@code false} to
    468      *            disable it.
    469      * @return the previous setting.
    470      * @see #resolveObject
    471      * @see ObjectOutputStream#enableReplaceObject
    472      */
    473     protected boolean enableResolveObject(boolean enable) {
    474         boolean originalValue = enableResolve;
    475         enableResolve = enable;
    476         return originalValue;
    477     }
    478 
    479     /**
    480      * Return the next {@code int} handle to be used to indicate cyclic
    481      * references being loaded from the stream.
    482      *
    483      * @return the next handle to represent the next cyclic reference
    484      */
    485     private int nextHandle() {
    486         return nextHandle++;
    487     }
    488 
    489     /**
    490      * Return the next token code (TC) from the receiver, which indicates what
    491      * kind of object follows
    492      *
    493      * @return the next TC from the receiver
    494      *
    495      * @throws IOException
    496      *             If an IO error occurs
    497      *
    498      * @see ObjectStreamConstants
    499      */
    500     private byte nextTC() throws IOException {
    501         if (hasPushbackTC) {
    502             hasPushbackTC = false; // We are consuming it
    503         } else {
    504             // Just in case a later call decides to really push it back,
    505             // we don't require the caller to pass it as parameter
    506             pushbackTC = input.readByte();
    507         }
    508         return pushbackTC;
    509     }
    510 
    511     /**
    512      * Pushes back the last TC code read
    513      */
    514     private void pushbackTC() {
    515         hasPushbackTC = true;
    516     }
    517 
    518     /**
    519      * Reads a single byte from the source stream and returns it as an integer
    520      * in the range from 0 to 255. Returns -1 if the end of the source stream
    521      * has been reached. Blocks if no input is available.
    522      *
    523      * @return the byte read or -1 if the end of the source stream has been
    524      *         reached.
    525      * @throws IOException
    526      *             if an error occurs while reading from this stream.
    527      */
    528     @Override
    529     public int read() throws IOException {
    530         checkReadPrimitiveTypes();
    531         return primitiveData.read();
    532     }
    533 
    534     /**
    535      * Reads at most {@code length} bytes from the source stream and stores them
    536      * in byte array {@code buffer} starting at offset {@code count}. Blocks
    537      * until {@code count} bytes have been read, the end of the source stream is
    538      * detected or an exception is thrown.
    539      *
    540      * @param buffer
    541      *            the array in which to store the bytes read.
    542      * @param offset
    543      *            the initial position in {@code buffer} to store the bytes
    544      *            read from the source stream.
    545      * @param length
    546      *            the maximum number of bytes to store in {@code buffer}.
    547      * @return the number of bytes read or -1 if the end of the source input
    548      *         stream has been reached.
    549      * @throws IndexOutOfBoundsException
    550      *             if {@code offset < 0} or {@code length < 0}, or if
    551      *             {@code offset + length} is greater than the length of
    552      *             {@code buffer}.
    553      * @throws IOException
    554      *             if an error occurs while reading from this stream.
    555      * @throws NullPointerException
    556      *             if {@code buffer} is {@code null}.
    557      */
    558     @Override
    559     public int read(byte[] buffer, int offset, int length) throws IOException {
    560         Arrays.checkOffsetAndCount(buffer.length, offset, length);
    561         if (length == 0) {
    562             return 0;
    563         }
    564         checkReadPrimitiveTypes();
    565         return primitiveData.read(buffer, offset, length);
    566     }
    567 
    568     /**
    569      * Reads and returns an array of raw bytes with primitive data. The array
    570      * will have up to 255 bytes. The primitive data will be in the format
    571      * described by {@code DataOutputStream}.
    572      *
    573      * @return The primitive data read, as raw bytes
    574      *
    575      * @throws IOException
    576      *             If an IO exception happened when reading the primitive data.
    577      */
    578     private byte[] readBlockData() throws IOException {
    579         byte[] result = new byte[input.readByte() & 0xff];
    580         input.readFully(result);
    581         return result;
    582     }
    583 
    584     /**
    585      * Reads and returns an array of raw bytes with primitive data. The array
    586      * will have more than 255 bytes. The primitive data will be in the format
    587      * described by {@code DataOutputStream}.
    588      *
    589      * @return The primitive data read, as raw bytes
    590      *
    591      * @throws IOException
    592      *             If an IO exception happened when reading the primitive data.
    593      */
    594     private byte[] readBlockDataLong() throws IOException {
    595         byte[] result = new byte[input.readInt()];
    596         input.readFully(result);
    597         return result;
    598     }
    599 
    600     /**
    601      * Reads a boolean from the source stream.
    602      *
    603      * @return the boolean value read from the source stream.
    604      * @throws EOFException
    605      *             if the end of the input is reached before the read
    606      *             request can be satisfied.
    607      * @throws IOException
    608      *             if an error occurs while reading from the source stream.
    609      */
    610     public boolean readBoolean() throws IOException {
    611         return primitiveTypes.readBoolean();
    612     }
    613 
    614     /**
    615      * Reads a byte (8 bit) from the source stream.
    616      *
    617      * @return the byte value read from the source stream.
    618      * @throws EOFException
    619      *             if the end of the input is reached before the read
    620      *             request can be satisfied.
    621      * @throws IOException
    622      *             if an error occurs while reading from the source stream.
    623      */
    624     public byte readByte() throws IOException {
    625         return primitiveTypes.readByte();
    626     }
    627 
    628     /**
    629      * Reads a character (16 bit) from the source stream.
    630      *
    631      * @return the char value read from the source stream.
    632      * @throws EOFException
    633      *             if the end of the input is reached before the read
    634      *             request can be satisfied.
    635      * @throws IOException
    636      *             if an error occurs while reading from the source stream.
    637      */
    638     public char readChar() throws IOException {
    639         return primitiveTypes.readChar();
    640     }
    641 
    642     /**
    643      * Reads and discards block data and objects until TC_ENDBLOCKDATA is found.
    644      *
    645      * @throws IOException
    646      *             If an IO exception happened when reading the optional class
    647      *             annotation.
    648      * @throws ClassNotFoundException
    649      *             If the class corresponding to the class descriptor could not
    650      *             be found.
    651      */
    652     private void discardData() throws ClassNotFoundException, IOException {
    653         primitiveData = emptyStream;
    654         boolean resolve = mustResolve;
    655         mustResolve = false;
    656         do {
    657             byte tc = nextTC();
    658             if (tc == TC_ENDBLOCKDATA) {
    659                 mustResolve = resolve;
    660                 return; // End of annotation
    661             }
    662             readContent(tc);
    663         } while (true);
    664     }
    665 
    666     /**
    667      * Reads a class descriptor (an {@code ObjectStreamClass}) from the
    668      * stream.
    669      *
    670      * @return the class descriptor read from the stream
    671      *
    672      * @throws IOException
    673      *             If an IO exception happened when reading the class
    674      *             descriptor.
    675      * @throws ClassNotFoundException
    676      *             If the class corresponding to the class descriptor could not
    677      *             be found.
    678      */
    679     private ObjectStreamClass readClassDesc() throws ClassNotFoundException, IOException {
    680         byte tc = nextTC();
    681         switch (tc) {
    682             case TC_CLASSDESC:
    683                 return readNewClassDesc(false);
    684             case TC_PROXYCLASSDESC:
    685                 Class<?> proxyClass = readNewProxyClassDesc();
    686                 ObjectStreamClass streamClass = ObjectStreamClass.lookup(proxyClass);
    687                 streamClass.setLoadFields(ObjectStreamClass.NO_FIELDS);
    688                 registerObjectRead(streamClass, nextHandle(), false);
    689                 checkedSetSuperClassDesc(streamClass, readClassDesc());
    690                 return streamClass;
    691             case TC_REFERENCE:
    692                 return (ObjectStreamClass) readCyclicReference();
    693             case TC_NULL:
    694                 return null;
    695             default:
    696                 throw corruptStream(tc);
    697         }
    698     }
    699 
    700     private StreamCorruptedException corruptStream(byte tc) throws StreamCorruptedException {
    701         throw new StreamCorruptedException("Wrong format: " + Integer.toHexString(tc & 0xff));
    702     }
    703 
    704     /**
    705      * Reads the content of the receiver based on the previously read token
    706      * {@code tc}.
    707      *
    708      * @param tc
    709      *            The token code for the next item in the stream
    710      * @return the object read from the stream
    711      *
    712      * @throws IOException
    713      *             If an IO exception happened when reading the class
    714      *             descriptor.
    715      * @throws ClassNotFoundException
    716      *             If the class corresponding to the object being read could not
    717      *             be found.
    718      */
    719     private Object readContent(byte tc) throws ClassNotFoundException,
    720             IOException {
    721         switch (tc) {
    722             case TC_BLOCKDATA:
    723                 return readBlockData();
    724             case TC_BLOCKDATALONG:
    725                 return readBlockDataLong();
    726             case TC_CLASS:
    727                 return readNewClass(false);
    728             case TC_CLASSDESC:
    729                 return readNewClassDesc(false);
    730             case TC_ARRAY:
    731                 return readNewArray(false);
    732             case TC_OBJECT:
    733                 return readNewObject(false);
    734             case TC_STRING:
    735                 return readNewString(false);
    736             case TC_LONGSTRING:
    737                 return readNewLongString(false);
    738             case TC_REFERENCE:
    739                 return readCyclicReference();
    740             case TC_NULL:
    741                 return null;
    742             case TC_EXCEPTION:
    743                 Exception exc = readException();
    744                 throw new WriteAbortedException("Read an exception", exc);
    745             case TC_RESET:
    746                 resetState();
    747                 return null;
    748             default:
    749                 throw corruptStream(tc);
    750         }
    751     }
    752 
    753     /**
    754      * Reads the content of the receiver based on the previously read token
    755      * {@code tc}. Primitive data content is considered an error.
    756      *
    757      * @param unshared
    758      *            read the object unshared
    759      * @return the object read from the stream
    760      *
    761      * @throws IOException
    762      *             If an IO exception happened when reading the class
    763      *             descriptor.
    764      * @throws ClassNotFoundException
    765      *             If the class corresponding to the object being read could not
    766      *             be found.
    767      */
    768     private Object readNonPrimitiveContent(boolean unshared)
    769             throws ClassNotFoundException, IOException {
    770         checkReadPrimitiveTypes();
    771         if (primitiveData.available() > 0) {
    772             OptionalDataException e = new OptionalDataException();
    773             e.length = primitiveData.available();
    774             throw e;
    775         }
    776 
    777         do {
    778             byte tc = nextTC();
    779             switch (tc) {
    780                 case TC_CLASS:
    781                     return readNewClass(unshared);
    782                 case TC_CLASSDESC:
    783                     return readNewClassDesc(unshared);
    784                 case TC_ARRAY:
    785                     return readNewArray(unshared);
    786                 case TC_OBJECT:
    787                     return readNewObject(unshared);
    788                 case TC_STRING:
    789                     return readNewString(unshared);
    790                 case TC_LONGSTRING:
    791                     return readNewLongString(unshared);
    792                 case TC_ENUM:
    793                     return readEnum(unshared);
    794                 case TC_REFERENCE:
    795                     if (unshared) {
    796                         readNewHandle();
    797                         throw new InvalidObjectException("Unshared read of back reference");
    798                     }
    799                     return readCyclicReference();
    800                 case TC_NULL:
    801                     return null;
    802                 case TC_EXCEPTION:
    803                     Exception exc = readException();
    804                     throw new WriteAbortedException("Read an exception", exc);
    805                 case TC_RESET:
    806                     resetState();
    807                     break;
    808                 case TC_ENDBLOCKDATA: // Can occur reading class annotation
    809                     pushbackTC();
    810                     OptionalDataException e = new OptionalDataException();
    811                     e.eof = true;
    812                     throw e;
    813                 default:
    814                     throw corruptStream(tc);
    815             }
    816             // Only TC_RESET falls through
    817         } while (true);
    818     }
    819 
    820     /**
    821      * Reads the next item from the stream assuming it is a cyclic reference to
    822      * an object previously read. Return the actual object previously read.
    823      *
    824      * @return the object previously read from the stream
    825      *
    826      * @throws IOException
    827      *             If an IO exception happened when reading the class
    828      *             descriptor.
    829      * @throws InvalidObjectException
    830      *             If the cyclic reference is not valid.
    831      */
    832     private Object readCyclicReference() throws InvalidObjectException, IOException {
    833         return registeredObjectRead(readNewHandle());
    834     }
    835 
    836     /**
    837      * Reads a double (64 bit) from the source stream.
    838      *
    839      * @return the double value read from the source stream.
    840      * @throws EOFException
    841      *             if the end of the input is reached before the read
    842      *             request can be satisfied.
    843      * @throws IOException
    844      *             if an error occurs while reading from the source stream.
    845      */
    846     public double readDouble() throws IOException {
    847         return primitiveTypes.readDouble();
    848     }
    849 
    850     /**
    851      * Read the next item assuming it is an exception. The exception is not a
    852      * regular instance in the object graph, but the exception instance that
    853      * happened (if any) when dumping the original object graph. The set of seen
    854      * objects will be reset just before and just after loading this exception
    855      * object.
    856      * <p>
    857      * When exceptions are found normally in the object graph, they are loaded
    858      * as a regular object, and not by this method. In that case, the set of
    859      * "known objects" is not reset.
    860      *
    861      * @return the exception read
    862      *
    863      * @throws IOException
    864      *             If an IO exception happened when reading the exception
    865      *             object.
    866      * @throws ClassNotFoundException
    867      *             If a class could not be found when reading the object graph
    868      *             for the exception
    869      * @throws OptionalDataException
    870      *             If optional data could not be found when reading the
    871      *             exception graph
    872      * @throws WriteAbortedException
    873      *             If another exception was caused when dumping this exception
    874      */
    875     private Exception readException() throws WriteAbortedException,
    876             OptionalDataException, ClassNotFoundException, IOException {
    877 
    878         resetSeenObjects();
    879 
    880         // Now we read the Throwable object that was saved
    881         // WARNING - the grammar says it is a Throwable, but the
    882         // WriteAbortedException constructor takes an Exception. So, we read an
    883         // Exception from the stream
    884         Exception exc = (Exception) readObject();
    885 
    886         // We reset the receiver's state (the grammar has "reset" in normal
    887         // font)
    888         resetSeenObjects();
    889         return exc;
    890     }
    891 
    892     /**
    893      * Reads a collection of field descriptors (name, type name, etc) for the
    894      * class descriptor {@code cDesc} (an {@code ObjectStreamClass})
    895      *
    896      * @param cDesc
    897      *            The class descriptor (an {@code ObjectStreamClass})
    898      *            for which to write field information
    899      *
    900      * @throws IOException
    901      *             If an IO exception happened when reading the field
    902      *             descriptors.
    903      * @throws ClassNotFoundException
    904      *             If a class for one of the field types could not be found
    905      *
    906      * @see #readObject()
    907      */
    908     private void readFieldDescriptors(ObjectStreamClass cDesc)
    909             throws ClassNotFoundException, IOException {
    910         short numFields = input.readShort();
    911         ObjectStreamField[] fields = new ObjectStreamField[numFields];
    912 
    913         // We set it now, but each element will be inserted in the array further
    914         // down
    915         cDesc.setLoadFields(fields);
    916 
    917         // Check ObjectOutputStream.writeFieldDescriptors
    918         for (short i = 0; i < numFields; i++) {
    919             char typecode = (char) input.readByte();
    920             String fieldName = input.readUTF();
    921             boolean isPrimType = ObjectStreamClass.isPrimitiveType(typecode);
    922             String classSig;
    923             if (isPrimType) {
    924                 classSig = String.valueOf(typecode);
    925             } else {
    926                 // The spec says it is a UTF, but experience shows they dump
    927                 // this String using writeObject (unlike the field name, which
    928                 // is saved with writeUTF).
    929                 // And if resolveObject is enabled, the classSig may be modified
    930                 // so that the original class descriptor cannot be read
    931                 // properly, so it is disabled.
    932                 boolean old = enableResolve;
    933                 try {
    934                     enableResolve = false;
    935                     classSig = (String) readObject();
    936                 } finally {
    937                     enableResolve = old;
    938                 }
    939             }
    940 
    941             classSig = formatClassSig(classSig);
    942             ObjectStreamField f = new ObjectStreamField(classSig, fieldName);
    943             fields[i] = f;
    944         }
    945     }
    946 
    947     /*
    948      * Format the class signature for ObjectStreamField, for example,
    949      * "[L[Ljava.lang.String;;" is converted to "[Ljava.lang.String;"
    950      */
    951     private static String formatClassSig(String classSig) {
    952         int start = 0;
    953         int end = classSig.length();
    954 
    955         if (end <= 0) {
    956             return classSig;
    957         }
    958 
    959         while (classSig.startsWith("[L", start)
    960                 && classSig.charAt(end - 1) == ';') {
    961             start += 2;
    962             end--;
    963         }
    964 
    965         if (start > 0) {
    966             start -= 2;
    967             end++;
    968             return classSig.substring(start, end);
    969         }
    970         return classSig;
    971     }
    972 
    973     /**
    974      * Reads the persistent fields of the object that is currently being read
    975      * from the source stream. The values read are stored in a GetField object
    976      * that provides access to the persistent fields. This GetField object is
    977      * then returned.
    978      *
    979      * @return the GetField object from which persistent fields can be accessed
    980      *         by name.
    981      * @throws ClassNotFoundException
    982      *             if the class of an object being deserialized can not be
    983      *             found.
    984      * @throws IOException
    985      *             if an error occurs while reading from this stream.
    986      * @throws NotActiveException
    987      *             if this stream is currently not reading an object.
    988      */
    989     public GetField readFields() throws IOException, ClassNotFoundException, NotActiveException {
    990         if (currentObject == null) {
    991             throw new NotActiveException();
    992         }
    993         EmulatedFieldsForLoading result = new EmulatedFieldsForLoading(currentClass);
    994         readFieldValues(result);
    995         return result;
    996     }
    997 
    998     /**
    999      * Reads a collection of field values for the emulated fields
   1000      * {@code emulatedFields}
   1001      *
   1002      * @param emulatedFields
   1003      *            an {@code EmulatedFieldsForLoading}, concrete subclass
   1004      *            of {@code GetField}
   1005      *
   1006      * @throws IOException
   1007      *             If an IO exception happened when reading the field values.
   1008      * @throws InvalidClassException
   1009      *             If an incompatible type is being assigned to an emulated
   1010      *             field.
   1011      * @throws OptionalDataException
   1012      *             If optional data could not be found when reading the
   1013      *             exception graph
   1014      *
   1015      * @see #readFields
   1016      * @see #readObject()
   1017      */
   1018     private void readFieldValues(EmulatedFieldsForLoading emulatedFields)
   1019             throws OptionalDataException, InvalidClassException, IOException {
   1020         EmulatedFields.ObjectSlot[] slots = emulatedFields.emulatedFields().slots();
   1021         for (ObjectSlot element : slots) {
   1022             element.defaulted = false;
   1023             Class<?> type = element.field.getType();
   1024             if (type == int.class) {
   1025                 element.fieldValue = input.readInt();
   1026             } else if (type == byte.class) {
   1027                 element.fieldValue = input.readByte();
   1028             } else if (type == char.class) {
   1029                 element.fieldValue = input.readChar();
   1030             } else if (type == short.class) {
   1031                 element.fieldValue = input.readShort();
   1032             } else if (type == boolean.class) {
   1033                 element.fieldValue = input.readBoolean();
   1034             } else if (type == long.class) {
   1035                 element.fieldValue = input.readLong();
   1036             } else if (type == float.class) {
   1037                 element.fieldValue = input.readFloat();
   1038             } else if (type == double.class) {
   1039                 element.fieldValue = input.readDouble();
   1040             } else {
   1041                 // Either array or Object
   1042                 try {
   1043                     element.fieldValue = readObject();
   1044                 } catch (ClassNotFoundException cnf) {
   1045                     // WARNING- Not sure this is the right thing to do. Write
   1046                     // test case.
   1047                     throw new InvalidClassException(cnf.toString());
   1048                 }
   1049             }
   1050         }
   1051     }
   1052 
   1053     /**
   1054      * Reads a collection of field values for the class descriptor
   1055      * {@code classDesc} (an {@code ObjectStreamClass}). The
   1056      * values will be used to set instance fields in object {@code obj}.
   1057      * This is the default mechanism, when emulated fields (an
   1058      * {@code GetField}) are not used. Actual values to load are stored
   1059      * directly into the object {@code obj}.
   1060      *
   1061      * @param obj
   1062      *            Instance in which the fields will be set.
   1063      * @param classDesc
   1064      *            A class descriptor (an {@code ObjectStreamClass})
   1065      *            defining which fields should be loaded.
   1066      *
   1067      * @throws IOException
   1068      *             If an IO exception happened when reading the field values.
   1069      * @throws InvalidClassException
   1070      *             If an incompatible type is being assigned to an emulated
   1071      *             field.
   1072      * @throws OptionalDataException
   1073      *             If optional data could not be found when reading the
   1074      *             exception graph
   1075      * @throws ClassNotFoundException
   1076      *             If a class of an object being de-serialized can not be found
   1077      *
   1078      * @see #readFields
   1079      * @see #readObject()
   1080      */
   1081     private void readFieldValues(Object obj, ObjectStreamClass classDesc) throws OptionalDataException, ClassNotFoundException, IOException {
   1082         // Now we must read all fields and assign them to the receiver
   1083         ObjectStreamField[] fields = classDesc.getLoadFields();
   1084         fields = (fields == null) ? ObjectStreamClass.NO_FIELDS : fields;
   1085         Class<?> declaringClass = classDesc.forClass();
   1086         if (declaringClass == null && mustResolve) {
   1087             throw new ClassNotFoundException(classDesc.getName());
   1088         }
   1089 
   1090         for (ObjectStreamField fieldDesc : fields) {
   1091             Field field = classDesc.getReflectionField(fieldDesc);
   1092             if (field != null && Modifier.isTransient(field.getModifiers())) {
   1093                 field = null; // No setting transient fields! (http://b/4471249)
   1094             }
   1095             // We may not have been able to find the field, or it may be transient, but we still
   1096             // need to read the value and do the other checking...
   1097             try {
   1098                 Class<?> type = fieldDesc.getTypeInternal();
   1099                 if (type == byte.class) {
   1100                     byte b = input.readByte();
   1101                     if (field != null) {
   1102                         field.setByte(obj, b);
   1103                     }
   1104                 } else if (type == char.class) {
   1105                     char c = input.readChar();
   1106                     if (field != null) {
   1107                         field.setChar(obj, c);
   1108                     }
   1109                 } else if (type == double.class) {
   1110                     double d = input.readDouble();
   1111                     if (field != null) {
   1112                         field.setDouble(obj, d);
   1113                     }
   1114                 } else if (type == float.class) {
   1115                     float f = input.readFloat();
   1116                     if (field != null) {
   1117                         field.setFloat(obj, f);
   1118                     }
   1119                 } else if (type == int.class) {
   1120                     int i = input.readInt();
   1121                     if (field != null) {
   1122                         field.setInt(obj, i);
   1123                     }
   1124                 } else if (type == long.class) {
   1125                     long j = input.readLong();
   1126                     if (field != null) {
   1127                         field.setLong(obj, j);
   1128                     }
   1129                 } else if (type == short.class) {
   1130                     short s = input.readShort();
   1131                     if (field != null) {
   1132                         field.setShort(obj, s);
   1133                     }
   1134                 } else if (type == boolean.class) {
   1135                     boolean z = input.readBoolean();
   1136                     if (field != null) {
   1137                         field.setBoolean(obj, z);
   1138                     }
   1139                 } else {
   1140                     Object toSet = fieldDesc.isUnshared() ? readUnshared() : readObject();
   1141                     if (toSet != null) {
   1142                         // Get the field type from the local field rather than
   1143                         // from the stream's supplied data. That's the field
   1144                         // we'll be setting, so that's the one that needs to be
   1145                         // validated.
   1146                         String fieldName = fieldDesc.getName();
   1147                         ObjectStreamField localFieldDesc = classDesc.getField(fieldName);
   1148                         Class<?> fieldType = localFieldDesc.getTypeInternal();
   1149                         Class<?> valueType = toSet.getClass();
   1150                         if (!fieldType.isAssignableFrom(valueType)) {
   1151                             throw new ClassCastException(classDesc.getName() + "." + fieldName + " - " + fieldType + " not compatible with " + valueType);
   1152                         }
   1153                         if (field != null) {
   1154                             field.set(obj, toSet);
   1155                         }
   1156                     }
   1157                 }
   1158             } catch (IllegalAccessException iae) {
   1159                 // ObjectStreamField should have called setAccessible(true).
   1160                 throw new AssertionError(iae);
   1161             } catch (NoSuchFieldError ignored) {
   1162             }
   1163         }
   1164     }
   1165 
   1166     /**
   1167      * Reads a float (32 bit) from the source stream.
   1168      *
   1169      * @return the float value read from the source stream.
   1170      * @throws EOFException
   1171      *             if the end of the input is reached before the read
   1172      *             request can be satisfied.
   1173      * @throws IOException
   1174      *             if an error occurs while reading from the source stream.
   1175      */
   1176     public float readFloat() throws IOException {
   1177         return primitiveTypes.readFloat();
   1178     }
   1179 
   1180     /**
   1181      * Reads bytes from the source stream into the byte array {@code dst}.
   1182      * This method will block until {@code dst.length} bytes have been read.
   1183      *
   1184      * @param dst
   1185      *            the array in which to store the bytes read.
   1186      * @throws EOFException
   1187      *             if the end of the input is reached before the read
   1188      *             request can be satisfied.
   1189      * @throws IOException
   1190      *             if an error occurs while reading from the source stream.
   1191      */
   1192     public void readFully(byte[] dst) throws IOException {
   1193         primitiveTypes.readFully(dst);
   1194     }
   1195 
   1196     /**
   1197      * Reads {@code byteCount} bytes from the source stream into the byte array {@code dst}.
   1198      *
   1199      * @param dst
   1200      *            the byte array in which to store the bytes read.
   1201      * @param offset
   1202      *            the initial position in {@code dst} to store the bytes
   1203      *            read from the source stream.
   1204      * @param byteCount
   1205      *            the number of bytes to read.
   1206      * @throws EOFException
   1207      *             if the end of the input is reached before the read
   1208      *             request can be satisfied.
   1209      * @throws IOException
   1210      *             if an error occurs while reading from the source stream.
   1211      */
   1212     public void readFully(byte[] dst, int offset, int byteCount) throws IOException {
   1213         primitiveTypes.readFully(dst, offset, byteCount);
   1214     }
   1215 
   1216     /**
   1217      * Walks the hierarchy of classes described by class descriptor
   1218      * {@code classDesc} and reads the field values corresponding to
   1219      * fields declared by the corresponding class descriptor. The instance to
   1220      * store field values into is {@code object}. If the class
   1221      * (corresponding to class descriptor {@code classDesc}) defines
   1222      * private instance method {@code readObject} it will be used to load
   1223      * field values.
   1224      *
   1225      * @param object
   1226      *            Instance into which stored field values loaded.
   1227      * @param classDesc
   1228      *            A class descriptor (an {@code ObjectStreamClass})
   1229      *            defining which fields should be loaded.
   1230      *
   1231      * @throws IOException
   1232      *             If an IO exception happened when reading the field values in
   1233      *             the hierarchy.
   1234      * @throws ClassNotFoundException
   1235      *             If a class for one of the field types could not be found
   1236      * @throws NotActiveException
   1237      *             If {@code defaultReadObject} is called from the wrong
   1238      *             context.
   1239      *
   1240      * @see #defaultReadObject
   1241      * @see #readObject()
   1242      */
   1243     private void readHierarchy(Object object, ObjectStreamClass classDesc)
   1244             throws IOException, ClassNotFoundException, NotActiveException {
   1245         if (object == null && mustResolve) {
   1246             throw new NotActiveException();
   1247         }
   1248 
   1249         List<ObjectStreamClass> streamClassList = classDesc.getHierarchy();
   1250         if (object == null) {
   1251             for (ObjectStreamClass objectStreamClass : streamClassList) {
   1252                 readObjectForClass(null, objectStreamClass);
   1253             }
   1254         } else {
   1255             List<Class<?>> superclasses = cachedSuperclasses.get(object.getClass());
   1256             if (superclasses == null) {
   1257                 superclasses = cacheSuperclassesFor(object.getClass());
   1258             }
   1259 
   1260             int lastIndex = 0;
   1261             for (int i = 0, end = superclasses.size(); i < end; ++i) {
   1262                 Class<?> superclass = superclasses.get(i);
   1263                 int index = findStreamSuperclass(superclass, streamClassList, lastIndex);
   1264                 if (index == -1) {
   1265                     readObjectNoData(object, superclass,
   1266                             ObjectStreamClass.lookupStreamClass(superclass));
   1267                 } else {
   1268                     for (int j = lastIndex; j <= index; j++) {
   1269                         readObjectForClass(object, streamClassList.get(j));
   1270                     }
   1271                     lastIndex = index + 1;
   1272                 }
   1273             }
   1274         }
   1275     }
   1276 
   1277     private HashMap<Class<?>, List<Class<?>>> cachedSuperclasses = new HashMap<Class<?>, List<Class<?>>>();
   1278 
   1279     private List<Class<?>> cacheSuperclassesFor(Class<?> c) {
   1280         ArrayList<Class<?>> result = new ArrayList<Class<?>>();
   1281         Class<?> nextClass = c;
   1282         while (nextClass != null) {
   1283             Class<?> testClass = nextClass.getSuperclass();
   1284             if (testClass != null) {
   1285                 result.add(0, nextClass);
   1286             }
   1287             nextClass = testClass;
   1288         }
   1289         cachedSuperclasses.put(c, result);
   1290         return result;
   1291     }
   1292 
   1293     private int findStreamSuperclass(Class<?> cl, List<ObjectStreamClass> classList, int lastIndex) {
   1294         for (int i = lastIndex, end = classList.size(); i < end; i++) {
   1295             ObjectStreamClass objCl = classList.get(i);
   1296             String forName = objCl.forClass().getName();
   1297 
   1298             if (objCl.getName().equals(forName)) {
   1299                 if (cl.getName().equals(objCl.getName())) {
   1300                     return i;
   1301                 }
   1302             } else {
   1303                 // there was a class replacement
   1304                 if (cl.getName().equals(forName)) {
   1305                     return i;
   1306                 }
   1307             }
   1308         }
   1309         return -1;
   1310     }
   1311 
   1312     private void readObjectNoData(Object object, Class<?> cl, ObjectStreamClass classDesc)
   1313             throws ObjectStreamException {
   1314         if (!classDesc.isSerializable()) {
   1315             return;
   1316         }
   1317         if (classDesc.hasMethodReadObjectNoData()){
   1318             final Method readMethod = classDesc.getMethodReadObjectNoData();
   1319             try {
   1320                 readMethod.invoke(object);
   1321             } catch (InvocationTargetException e) {
   1322                 Throwable ex = e.getTargetException();
   1323                 if (ex instanceof RuntimeException) {
   1324                     throw (RuntimeException) ex;
   1325                 } else if (ex instanceof Error) {
   1326                     throw (Error) ex;
   1327                 }
   1328                 throw (ObjectStreamException) ex;
   1329             } catch (IllegalAccessException e) {
   1330                 throw new RuntimeException(e.toString());
   1331             }
   1332         }
   1333 
   1334     }
   1335 
   1336     private void readObjectForClass(Object object, ObjectStreamClass classDesc)
   1337             throws IOException, ClassNotFoundException, NotActiveException {
   1338         // Have to do this before calling defaultReadObject or anything that
   1339         // calls defaultReadObject
   1340         currentObject = object;
   1341         currentClass = classDesc;
   1342 
   1343         boolean hadWriteMethod = (classDesc.getFlags() & SC_WRITE_METHOD) != 0;
   1344         Class<?> targetClass = classDesc.forClass();
   1345 
   1346         final Method readMethod;
   1347         if (targetClass == null || !mustResolve) {
   1348             readMethod = null;
   1349         } else {
   1350             readMethod = classDesc.getMethodReadObject();
   1351         }
   1352         try {
   1353             if (readMethod != null) {
   1354                 // We have to be able to fetch its value, even if it is private
   1355                 readMethod.setAccessible(true);
   1356                 try {
   1357                     readMethod.invoke(object, this);
   1358                 } catch (InvocationTargetException e) {
   1359                     Throwable ex = e.getTargetException();
   1360                     if (ex instanceof ClassNotFoundException) {
   1361                         throw (ClassNotFoundException) ex;
   1362                     } else if (ex instanceof RuntimeException) {
   1363                         throw (RuntimeException) ex;
   1364                     } else if (ex instanceof Error) {
   1365                         throw (Error) ex;
   1366                     }
   1367                     throw (IOException) ex;
   1368                 } catch (IllegalAccessException e) {
   1369                     throw new RuntimeException(e.toString());
   1370                 }
   1371             } else {
   1372                 defaultReadObject();
   1373             }
   1374             if (hadWriteMethod) {
   1375                 discardData();
   1376             }
   1377         } finally {
   1378             // Cleanup, needs to run always so that we can later detect invalid
   1379             // calls to defaultReadObject
   1380             currentObject = null; // We did not set this, so we do not need to
   1381             // clean it
   1382             currentClass = null;
   1383         }
   1384     }
   1385 
   1386     /**
   1387      * Reads an integer (32 bit) from the source stream.
   1388      *
   1389      * @return the integer value read from the source stream.
   1390      * @throws EOFException
   1391      *             if the end of the input is reached before the read
   1392      *             request can be satisfied.
   1393      * @throws IOException
   1394      *             if an error occurs while reading from the source stream.
   1395      */
   1396     public int readInt() throws IOException {
   1397         return primitiveTypes.readInt();
   1398     }
   1399 
   1400     /**
   1401      * Reads the next line from the source stream. Lines are terminated by
   1402      * {@code '\r'}, {@code '\n'}, {@code "\r\n"} or an {@code EOF}.
   1403      *
   1404      * @return the string read from the source stream.
   1405      * @throws IOException
   1406      *             if an error occurs while reading from the source stream.
   1407      * @deprecated Use {@link BufferedReader}
   1408      */
   1409     @Deprecated
   1410     public String readLine() throws IOException {
   1411         return primitiveTypes.readLine();
   1412     }
   1413 
   1414     /**
   1415      * Reads a long (64 bit) from the source stream.
   1416      *
   1417      * @return the long value read from the source stream.
   1418      * @throws EOFException
   1419      *             if the end of the input is reached before the read
   1420      *             request can be satisfied.
   1421      * @throws IOException
   1422      *             if an error occurs while reading from the source stream.
   1423      */
   1424     public long readLong() throws IOException {
   1425         return primitiveTypes.readLong();
   1426     }
   1427 
   1428     /**
   1429      * Read a new array from the receiver. It is assumed the array has not been
   1430      * read yet (not a cyclic reference). Return the array read.
   1431      *
   1432      * @param unshared
   1433      *            read the object unshared
   1434      * @return the array read
   1435      *
   1436      * @throws IOException
   1437      *             If an IO exception happened when reading the array.
   1438      * @throws ClassNotFoundException
   1439      *             If a class for one of the objects could not be found
   1440      * @throws OptionalDataException
   1441      *             If optional data could not be found when reading the array.
   1442      */
   1443     private Object readNewArray(boolean unshared) throws OptionalDataException,
   1444             ClassNotFoundException, IOException {
   1445         ObjectStreamClass classDesc = readClassDesc();
   1446 
   1447         if (classDesc == null) {
   1448             throw missingClassDescriptor();
   1449         }
   1450 
   1451         int newHandle = nextHandle();
   1452 
   1453         // Array size
   1454         int size = input.readInt();
   1455         Class<?> arrayClass = classDesc.forClass();
   1456         Class<?> componentType = arrayClass.getComponentType();
   1457         Object result = Array.newInstance(componentType, size);
   1458 
   1459         registerObjectRead(result, newHandle, unshared);
   1460 
   1461         // Now we have code duplication just because Java is typed. We have to
   1462         // read N elements and assign to array positions, but we must typecast
   1463         // the array first, and also call different methods depending on the
   1464         // elements.
   1465         if (componentType.isPrimitive()) {
   1466             if (componentType == int.class) {
   1467                 int[] intArray = (int[]) result;
   1468                 for (int i = 0; i < size; i++) {
   1469                     intArray[i] = input.readInt();
   1470                 }
   1471             } else if (componentType == byte.class) {
   1472                 byte[] byteArray = (byte[]) result;
   1473                 input.readFully(byteArray, 0, size);
   1474             } else if (componentType == char.class) {
   1475                 char[] charArray = (char[]) result;
   1476                 for (int i = 0; i < size; i++) {
   1477                     charArray[i] = input.readChar();
   1478                 }
   1479             } else if (componentType == short.class) {
   1480                 short[] shortArray = (short[]) result;
   1481                 for (int i = 0; i < size; i++) {
   1482                     shortArray[i] = input.readShort();
   1483                 }
   1484             } else if (componentType == boolean.class) {
   1485                 boolean[] booleanArray = (boolean[]) result;
   1486                 for (int i = 0; i < size; i++) {
   1487                     booleanArray[i] = input.readBoolean();
   1488                 }
   1489             } else if (componentType == long.class) {
   1490                 long[] longArray = (long[]) result;
   1491                 for (int i = 0; i < size; i++) {
   1492                     longArray[i] = input.readLong();
   1493                 }
   1494             } else if (componentType == float.class) {
   1495                 float[] floatArray = (float[]) result;
   1496                 for (int i = 0; i < size; i++) {
   1497                     floatArray[i] = input.readFloat();
   1498                 }
   1499             } else if (componentType == double.class) {
   1500                 double[] doubleArray = (double[]) result;
   1501                 for (int i = 0; i < size; i++) {
   1502                     doubleArray[i] = input.readDouble();
   1503                 }
   1504             } else {
   1505                 throw new ClassNotFoundException("Wrong base type in " + classDesc.getName());
   1506             }
   1507         } else {
   1508             // Array of Objects
   1509             Object[] objectArray = (Object[]) result;
   1510             for (int i = 0; i < size; i++) {
   1511                 // TODO: This place is the opportunity for enhancement
   1512                 //      We can implement writing elements through fast-path,
   1513                 //      without setting up the context (see readObject()) for
   1514                 //      each element with public API
   1515                 objectArray[i] = readObject();
   1516             }
   1517         }
   1518         if (enableResolve) {
   1519             result = resolveObject(result);
   1520             registerObjectRead(result, newHandle, false);
   1521         }
   1522         return result;
   1523     }
   1524 
   1525     /**
   1526      * Reads a new class from the receiver. It is assumed the class has not been
   1527      * read yet (not a cyclic reference). Return the class read.
   1528      *
   1529      * @param unshared
   1530      *            read the object unshared
   1531      * @return The {@code java.lang.Class} read from the stream.
   1532      *
   1533      * @throws IOException
   1534      *             If an IO exception happened when reading the class.
   1535      * @throws ClassNotFoundException
   1536      *             If a class for one of the objects could not be found
   1537      */
   1538     private Class<?> readNewClass(boolean unshared) throws ClassNotFoundException, IOException {
   1539         ObjectStreamClass classDesc = readClassDesc();
   1540         if (classDesc == null) {
   1541             throw missingClassDescriptor();
   1542         }
   1543         Class<?> localClass = classDesc.forClass();
   1544         if (localClass != null) {
   1545             registerObjectRead(localClass, nextHandle(), unshared);
   1546         }
   1547         return localClass;
   1548     }
   1549 
   1550     /*
   1551      * read class type for Enum, note there's difference between enum and normal
   1552      * classes
   1553      */
   1554     private ObjectStreamClass readEnumDesc() throws IOException,
   1555             ClassNotFoundException {
   1556         byte tc = nextTC();
   1557         switch (tc) {
   1558             case TC_CLASSDESC:
   1559                 return readEnumDescInternal();
   1560             case TC_REFERENCE:
   1561                 return (ObjectStreamClass) readCyclicReference();
   1562             case TC_NULL:
   1563                 return null;
   1564             default:
   1565                 throw corruptStream(tc);
   1566         }
   1567     }
   1568 
   1569     private ObjectStreamClass readEnumDescInternal() throws IOException, ClassNotFoundException {
   1570         ObjectStreamClass classDesc;
   1571         primitiveData = input;
   1572         int oldHandle = descriptorHandle;
   1573         descriptorHandle = nextHandle();
   1574         classDesc = readClassDescriptor();
   1575         registerObjectRead(classDesc, descriptorHandle, false);
   1576         descriptorHandle = oldHandle;
   1577         primitiveData = emptyStream;
   1578         classDesc.setClass(resolveClass(classDesc));
   1579         // Consume unread class annotation data and TC_ENDBLOCKDATA
   1580         discardData();
   1581         ObjectStreamClass superClass = readClassDesc();
   1582         checkedSetSuperClassDesc(classDesc, superClass);
   1583         // Check SUIDs, note all SUID for Enum is 0L
   1584         if (0L != classDesc.getSerialVersionUID() || 0L != superClass.getSerialVersionUID()) {
   1585             throw new InvalidClassException(superClass.getName(),
   1586                     "Incompatible class (SUID): " + superClass + " but expected " + superClass);
   1587         }
   1588         byte tc = nextTC();
   1589         // discard TC_ENDBLOCKDATA after classDesc if any
   1590         if (tc == TC_ENDBLOCKDATA) {
   1591             // read next parent class. For enum, it may be null
   1592             superClass.setSuperclass(readClassDesc());
   1593         } else {
   1594             // not TC_ENDBLOCKDATA, push back for next read
   1595             pushbackTC();
   1596         }
   1597         return classDesc;
   1598     }
   1599 
   1600     @SuppressWarnings("unchecked")// For the Enum.valueOf call
   1601     private Object readEnum(boolean unshared) throws OptionalDataException,
   1602             ClassNotFoundException, IOException {
   1603         // read classdesc for Enum first
   1604         ObjectStreamClass classDesc = readEnumDesc();
   1605         int newHandle = nextHandle();
   1606         // read name after class desc
   1607         String name;
   1608         byte tc = nextTC();
   1609         switch (tc) {
   1610             case TC_REFERENCE:
   1611                 if (unshared) {
   1612                     readNewHandle();
   1613                     throw new InvalidObjectException("Unshared read of back reference");
   1614                 }
   1615                 name = (String) readCyclicReference();
   1616                 break;
   1617             case TC_STRING:
   1618                 name = (String) readNewString(unshared);
   1619                 break;
   1620             default:
   1621                 throw corruptStream(tc);
   1622         }
   1623 
   1624         Enum<?> result;
   1625         try {
   1626             result = Enum.valueOf((Class) classDesc.forClass(), name);
   1627         } catch (IllegalArgumentException e) {
   1628             throw new InvalidObjectException(e.getMessage());
   1629         }
   1630         registerObjectRead(result, newHandle, unshared);
   1631         return result;
   1632     }
   1633 
   1634     /**
   1635      * Reads a new class descriptor from the receiver. It is assumed the class
   1636      * descriptor has not been read yet (not a cyclic reference). Return the
   1637      * class descriptor read.
   1638      *
   1639      * @param unshared
   1640      *            read the object unshared
   1641      * @return The {@code ObjectStreamClass} read from the stream.
   1642      *
   1643      * @throws IOException
   1644      *             If an IO exception happened when reading the class
   1645      *             descriptor.
   1646      * @throws ClassNotFoundException
   1647      *             If a class for one of the objects could not be found
   1648      */
   1649     private ObjectStreamClass readNewClassDesc(boolean unshared)
   1650             throws ClassNotFoundException, IOException {
   1651         // So read...() methods can be used by
   1652         // subclasses during readClassDescriptor()
   1653         primitiveData = input;
   1654         int oldHandle = descriptorHandle;
   1655         descriptorHandle = nextHandle();
   1656         ObjectStreamClass newClassDesc = readClassDescriptor();
   1657         registerObjectRead(newClassDesc, descriptorHandle, unshared);
   1658         descriptorHandle = oldHandle;
   1659         primitiveData = emptyStream;
   1660 
   1661         // We need to map classDesc to class.
   1662         try {
   1663             newClassDesc.setClass(resolveClass(newClassDesc));
   1664             // Check SUIDs & base name of the class
   1665             verifyAndInit(newClassDesc);
   1666         } catch (ClassNotFoundException e) {
   1667             if (mustResolve) {
   1668                 throw e;
   1669                 // Just continue, the class may not be required
   1670             }
   1671         }
   1672 
   1673         // Resolve the field signatures using the class loader of the
   1674         // resolved class
   1675         ObjectStreamField[] fields = newClassDesc.getLoadFields();
   1676         fields = (fields == null) ? ObjectStreamClass.NO_FIELDS : fields;
   1677         ClassLoader loader = newClassDesc.forClass() == null ? callerClassLoader
   1678                 : newClassDesc.forClass().getClassLoader();
   1679         for (ObjectStreamField element : fields) {
   1680             element.resolve(loader);
   1681         }
   1682 
   1683         // Consume unread class annotation data and TC_ENDBLOCKDATA
   1684         discardData();
   1685         checkedSetSuperClassDesc(newClassDesc, readClassDesc());
   1686         return newClassDesc;
   1687     }
   1688 
   1689     /**
   1690      * Reads a new proxy class descriptor from the receiver. It is assumed the
   1691      * proxy class descriptor has not been read yet (not a cyclic reference).
   1692      * Return the proxy class descriptor read.
   1693      *
   1694      * @return The {@code Class} read from the stream.
   1695      *
   1696      * @throws IOException
   1697      *             If an IO exception happened when reading the class
   1698      *             descriptor.
   1699      * @throws ClassNotFoundException
   1700      *             If a class for one of the objects could not be found
   1701      */
   1702     private Class<?> readNewProxyClassDesc() throws ClassNotFoundException,
   1703             IOException {
   1704         int count = input.readInt();
   1705         String[] interfaceNames = new String[count];
   1706         for (int i = 0; i < count; i++) {
   1707             interfaceNames[i] = input.readUTF();
   1708         }
   1709         Class<?> proxy = resolveProxyClass(interfaceNames);
   1710         // Consume unread class annotation data and TC_ENDBLOCKDATA
   1711         discardData();
   1712         return proxy;
   1713     }
   1714 
   1715     /**
   1716      * Reads a class descriptor from the source stream.
   1717      *
   1718      * @return the class descriptor read from the source stream.
   1719      * @throws ClassNotFoundException
   1720      *             if a class for one of the objects cannot be found.
   1721      * @throws IOException
   1722      *             if an error occurs while reading from the source stream.
   1723      */
   1724     protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException {
   1725         ObjectStreamClass newClassDesc = new ObjectStreamClass();
   1726         String name = input.readUTF();
   1727         if (name.length() == 0) {
   1728             throw new IOException("The stream is corrupted");
   1729         }
   1730         newClassDesc.setName(name);
   1731         newClassDesc.setSerialVersionUID(input.readLong());
   1732         newClassDesc.setFlags(input.readByte());
   1733 
   1734         /*
   1735          * We must register the class descriptor before reading field
   1736          * descriptors. If called outside of readObject, the descriptorHandle
   1737          * might be unset.
   1738          */
   1739         if (descriptorHandle == -1) {
   1740             descriptorHandle = nextHandle();
   1741         }
   1742         registerObjectRead(newClassDesc, descriptorHandle, false);
   1743 
   1744         readFieldDescriptors(newClassDesc);
   1745         return newClassDesc;
   1746     }
   1747 
   1748     /**
   1749      * Creates the proxy class that implements the interfaces specified in
   1750      * {@code interfaceNames}.
   1751      *
   1752      * @param interfaceNames
   1753      *            the interfaces used to create the proxy class.
   1754      * @return the proxy class.
   1755      * @throws ClassNotFoundException
   1756      *             if the proxy class or any of the specified interfaces cannot
   1757      *             be created.
   1758      * @throws IOException
   1759      *             if an error occurs while reading from the source stream.
   1760      * @see ObjectOutputStream#annotateProxyClass(Class)
   1761      */
   1762     protected Class<?> resolveProxyClass(String[] interfaceNames)
   1763             throws IOException, ClassNotFoundException {
   1764         // TODO: This method is opportunity for performance enhancement
   1765         //       We can cache the classloader and recently used interfaces.
   1766         ClassLoader loader = ClassLoader.getSystemClassLoader();
   1767         Class<?>[] interfaces = new Class<?>[interfaceNames.length];
   1768         for (int i = 0; i < interfaceNames.length; i++) {
   1769             interfaces[i] = Class.forName(interfaceNames[i], false, loader);
   1770         }
   1771         try {
   1772             return Proxy.getProxyClass(loader, interfaces);
   1773         } catch (IllegalArgumentException e) {
   1774             throw new ClassNotFoundException(e.toString(), e);
   1775         }
   1776     }
   1777 
   1778     private int readNewHandle() throws IOException {
   1779         return input.readInt();
   1780     }
   1781 
   1782     /**
   1783      * Read a new object from the stream. It is assumed the object has not been
   1784      * loaded yet (not a cyclic reference). Return the object read.
   1785      *
   1786      * If the object implements <code>Externalizable</code> its
   1787      * <code>readExternal</code> is called. Otherwise, all fields described by
   1788      * the class hierarchy are loaded. Each class can define how its declared
   1789      * instance fields are loaded by defining a private method
   1790      * <code>readObject</code>
   1791      *
   1792      * @param unshared
   1793      *            read the object unshared
   1794      * @return the object read
   1795      *
   1796      * @throws IOException
   1797      *             If an IO exception happened when reading the object.
   1798      * @throws OptionalDataException
   1799      *             If optional data could not be found when reading the object
   1800      *             graph
   1801      * @throws ClassNotFoundException
   1802      *             If a class for one of the objects could not be found
   1803      */
   1804     private Object readNewObject(boolean unshared)
   1805             throws OptionalDataException, ClassNotFoundException, IOException {
   1806         ObjectStreamClass classDesc = readClassDesc();
   1807 
   1808         if (classDesc == null) {
   1809             throw missingClassDescriptor();
   1810         }
   1811 
   1812         int newHandle = nextHandle();
   1813         Class<?> objectClass = classDesc.forClass();
   1814         Object result = null;
   1815         Object registeredResult = null;
   1816         if (objectClass != null) {
   1817             // Now we know which class to instantiate and which constructor to
   1818             // run. We are allowed to run the constructor.
   1819             result = classDesc.newInstance(objectClass);
   1820             registerObjectRead(result, newHandle, unshared);
   1821             registeredResult = result;
   1822         } else {
   1823             result = null;
   1824         }
   1825 
   1826         try {
   1827             // This is how we know what to do in defaultReadObject. And it is
   1828             // also used by defaultReadObject to check if it was called from an
   1829             // invalid place. It also allows readExternal to call
   1830             // defaultReadObject and have it work.
   1831             currentObject = result;
   1832             currentClass = classDesc;
   1833 
   1834             // If Externalizable, just let the object read itself
   1835             // Note that this value comes from the Stream, and in fact it could be
   1836             // that the classes have been changed so that the info below now
   1837             // conflicts with the newer class
   1838             boolean wasExternalizable = (classDesc.getFlags() & SC_EXTERNALIZABLE) != 0;
   1839             if (wasExternalizable) {
   1840                 boolean blockData = (classDesc.getFlags() & SC_BLOCK_DATA) != 0;
   1841                 if (!blockData) {
   1842                     primitiveData = input;
   1843                 }
   1844                 if (mustResolve) {
   1845                     Externalizable extern = (Externalizable) result;
   1846                     extern.readExternal(this);
   1847                 }
   1848                 if (blockData) {
   1849                     // Similar to readHierarchy. Anything not read by
   1850                     // readExternal has to be consumed here
   1851                     discardData();
   1852                 } else {
   1853                     primitiveData = emptyStream;
   1854                 }
   1855             } else {
   1856                 // If we got here, it is Serializable but not Externalizable.
   1857                 // Walk the hierarchy reading each class' slots
   1858                 readHierarchy(result, classDesc);
   1859             }
   1860         } finally {
   1861             // Cleanup, needs to run always so that we can later detect invalid
   1862             // calls to defaultReadObject
   1863             currentObject = null;
   1864             currentClass = null;
   1865         }
   1866 
   1867         if (objectClass != null) {
   1868 
   1869             if (classDesc.hasMethodReadResolve()){
   1870                 Method methodReadResolve = classDesc.getMethodReadResolve();
   1871                 try {
   1872                     result = methodReadResolve.invoke(result, (Object[]) null);
   1873                 } catch (IllegalAccessException ignored) {
   1874                 } catch (InvocationTargetException ite) {
   1875                     Throwable target = ite.getTargetException();
   1876                     if (target instanceof ObjectStreamException) {
   1877                         throw (ObjectStreamException) target;
   1878                     } else if (target instanceof Error) {
   1879                         throw (Error) target;
   1880                     } else {
   1881                         throw (RuntimeException) target;
   1882                     }
   1883                 }
   1884 
   1885             }
   1886         }
   1887         // We get here either if class-based replacement was not needed or if it
   1888         // was needed but produced the same object or if it could not be
   1889         // computed.
   1890 
   1891         // The object to return is the one we instantiated or a replacement for
   1892         // it
   1893         if (result != null && enableResolve) {
   1894             result = resolveObject(result);
   1895         }
   1896         if (registeredResult != result) {
   1897             registerObjectRead(result, newHandle, unshared);
   1898         }
   1899         return result;
   1900     }
   1901 
   1902     private InvalidClassException missingClassDescriptor() throws InvalidClassException {
   1903         throw new InvalidClassException("Read null attempting to read class descriptor for object");
   1904     }
   1905 
   1906     /**
   1907      * Read a string encoded in {@link DataInput modified UTF-8} from the
   1908      * receiver. Return the string read.
   1909      *
   1910      * @param unshared
   1911      *            read the object unshared
   1912      * @return the string just read.
   1913      * @throws IOException
   1914      *             If an IO exception happened when reading the String.
   1915      */
   1916     private Object readNewString(boolean unshared) throws IOException {
   1917         Object result = input.readUTF();
   1918         if (enableResolve) {
   1919             result = resolveObject(result);
   1920         }
   1921         registerObjectRead(result, nextHandle(), unshared);
   1922 
   1923         return result;
   1924     }
   1925 
   1926     /**
   1927      * Read a new String in UTF format from the receiver. Return the string
   1928      * read.
   1929      *
   1930      * @param unshared
   1931      *            read the object unshared
   1932      * @return the string just read.
   1933      *
   1934      * @throws IOException
   1935      *             If an IO exception happened when reading the String.
   1936      */
   1937     private Object readNewLongString(boolean unshared) throws IOException {
   1938         long length = input.readLong();
   1939         Object result = input.decodeUTF((int) length);
   1940         if (enableResolve) {
   1941             result = resolveObject(result);
   1942         }
   1943         registerObjectRead(result, nextHandle(), unshared);
   1944 
   1945         return result;
   1946     }
   1947 
   1948     /**
   1949      * Reads the next object from the source stream.
   1950      *
   1951      * @return the object read from the source stream.
   1952      * @throws ClassNotFoundException
   1953      *             if the class of one of the objects in the object graph cannot
   1954      *             be found.
   1955      * @throws IOException
   1956      *             if an error occurs while reading from the source stream.
   1957      * @throws OptionalDataException
   1958      *             if primitive data types were found instead of an object.
   1959      * @see ObjectOutputStream#writeObject(Object)
   1960      */
   1961     public final Object readObject() throws OptionalDataException,
   1962             ClassNotFoundException, IOException {
   1963         return readObject(false);
   1964     }
   1965 
   1966     /**
   1967      * Reads the next unshared object from the source stream.
   1968      *
   1969      * @return the new object read.
   1970      * @throws ClassNotFoundException
   1971      *             if the class of one of the objects in the object graph cannot
   1972      *             be found.
   1973      * @throws IOException
   1974      *             if an error occurs while reading from the source stream.
   1975      * @see ObjectOutputStream#writeUnshared
   1976      */
   1977     public Object readUnshared() throws IOException, ClassNotFoundException {
   1978         return readObject(true);
   1979     }
   1980 
   1981     private Object readObject(boolean unshared) throws OptionalDataException,
   1982             ClassNotFoundException, IOException {
   1983         boolean restoreInput = (primitiveData == input);
   1984         if (restoreInput) {
   1985             primitiveData = emptyStream;
   1986         }
   1987 
   1988         // This is the spec'ed behavior in JDK 1.2. Very bizarre way to allow
   1989         // behavior overriding.
   1990         if (subclassOverridingImplementation && !unshared) {
   1991             return readObjectOverride();
   1992         }
   1993 
   1994         // If we still had primitive types to read, should we discard them
   1995         // (reset the primitiveTypes stream) or leave as is, so that attempts to
   1996         // read primitive types won't read 'past data' ???
   1997         Object result;
   1998         try {
   1999             // We need this so we can tell when we are returning to the
   2000             // original/outside caller
   2001             if (++nestedLevels == 1) {
   2002                 // Remember the caller's class loader
   2003                 callerClassLoader = getClosestUserClassLoader();
   2004             }
   2005 
   2006             result = readNonPrimitiveContent(unshared);
   2007             if (restoreInput) {
   2008                 primitiveData = input;
   2009             }
   2010         } finally {
   2011             // We need this so we can tell when we are returning to the
   2012             // original/outside caller
   2013             if (--nestedLevels == 0) {
   2014                 // We are going to return to the original caller, perform
   2015                 // cleanups.
   2016                 // No more need to remember the caller's class loader
   2017                 callerClassLoader = null;
   2018             }
   2019         }
   2020 
   2021         // Done reading this object. Is it time to return to the original
   2022         // caller? If so we need to perform validations first.
   2023         if (nestedLevels == 0 && validations != null) {
   2024             // We are going to return to the original caller. If validation is
   2025             // enabled we need to run them now and then cleanup the validation
   2026             // collection
   2027             try {
   2028                 for (InputValidationDesc element : validations) {
   2029                     element.validator.validateObject();
   2030                 }
   2031             } finally {
   2032                 // Validations have to be renewed, since they are only called
   2033                 // from readObject
   2034                 validations = null;
   2035             }
   2036         }
   2037         return result;
   2038     }
   2039 
   2040     private static final ClassLoader bootstrapLoader = Object.class.getClassLoader();
   2041     private static final ClassLoader systemLoader = ClassLoader.getSystemClassLoader();
   2042 
   2043     /**
   2044      * Searches up the call stack to find the closest user-defined class loader.
   2045      *
   2046      * @return a user-defined class loader or null if one isn't found
   2047      */
   2048     private static ClassLoader getClosestUserClassLoader() {
   2049         Class<?>[] stackClasses = VMStack.getClasses(-1);
   2050         for (Class<?> stackClass : stackClasses) {
   2051             ClassLoader loader = stackClass.getClassLoader();
   2052             if (loader != null && loader != bootstrapLoader
   2053                     && loader != systemLoader) {
   2054                 return loader;
   2055             }
   2056         }
   2057         return null;
   2058     }
   2059 
   2060     /**
   2061      * Method to be overridden by subclasses to read the next object from the
   2062      * source stream.
   2063      *
   2064      * @return the object read from the source stream.
   2065      * @throws ClassNotFoundException
   2066      *             if the class of one of the objects in the object graph cannot
   2067      *             be found.
   2068      * @throws IOException
   2069      *             if an error occurs while reading from the source stream.
   2070      * @throws OptionalDataException
   2071      *             if primitive data types were found instead of an object.
   2072      * @see ObjectOutputStream#writeObjectOverride
   2073      */
   2074     protected Object readObjectOverride() throws OptionalDataException,
   2075             ClassNotFoundException, IOException {
   2076         if (input == null) {
   2077             return null;
   2078         }
   2079         // Subclasses must override.
   2080         throw new IOException();
   2081     }
   2082 
   2083     /**
   2084      * Reads a short (16 bit) from the source stream.
   2085      *
   2086      * @return the short value read from the source stream.
   2087      * @throws IOException
   2088      *             if an error occurs while reading from the source stream.
   2089      */
   2090     public short readShort() throws IOException {
   2091         return primitiveTypes.readShort();
   2092     }
   2093 
   2094     /**
   2095      * Reads and validates the ObjectInputStream header from the source stream.
   2096      *
   2097      * @throws IOException
   2098      *             if an error occurs while reading from the source stream.
   2099      * @throws StreamCorruptedException
   2100      *             if the source stream does not contain readable serialized
   2101      *             objects.
   2102      */
   2103     protected void readStreamHeader() throws IOException,
   2104             StreamCorruptedException {
   2105         if (input.readShort() == STREAM_MAGIC
   2106                 && input.readShort() == STREAM_VERSION) {
   2107             return;
   2108         }
   2109         throw new StreamCorruptedException();
   2110     }
   2111 
   2112     /**
   2113      * Reads an unsigned byte (8 bit) from the source stream.
   2114      *
   2115      * @return the unsigned byte value read from the source stream packaged in
   2116      *         an integer.
   2117      * @throws EOFException
   2118      *             if the end of the input is reached before the read
   2119      *             request can be satisfied.
   2120      * @throws IOException
   2121      *             if an error occurs while reading from the source stream.
   2122      */
   2123     public int readUnsignedByte() throws IOException {
   2124         return primitiveTypes.readUnsignedByte();
   2125     }
   2126 
   2127     /**
   2128      * Reads an unsigned short (16 bit) from the source stream.
   2129      *
   2130      * @return the unsigned short value read from the source stream packaged in
   2131      *         an integer.
   2132      * @throws EOFException
   2133      *             if the end of the input is reached before the read
   2134      *             request can be satisfied.
   2135      * @throws IOException
   2136      *             if an error occurs while reading from the source stream.
   2137      */
   2138     public int readUnsignedShort() throws IOException {
   2139         return primitiveTypes.readUnsignedShort();
   2140     }
   2141 
   2142     /**
   2143      * Reads a string encoded in {@link DataInput modified UTF-8} from the
   2144      * source stream.
   2145      *
   2146      * @return the string encoded in {@link DataInput modified UTF-8} read from
   2147      *         the source stream.
   2148      * @throws EOFException
   2149      *             if the end of the input is reached before the read
   2150      *             request can be satisfied.
   2151      * @throws IOException
   2152      *             if an error occurs while reading from the source stream.
   2153      */
   2154     public String readUTF() throws IOException {
   2155         return primitiveTypes.readUTF();
   2156     }
   2157 
   2158     /**
   2159      * Returns the previously-read object corresponding to the given serialization handle.
   2160      * @throws InvalidObjectException
   2161      *             If there is no previously-read object with this handle
   2162      */
   2163     private Object registeredObjectRead(int handle) throws InvalidObjectException {
   2164         Object res = objectsRead.get(handle - ObjectStreamConstants.baseWireHandle);
   2165         if (res == UNSHARED_OBJ) {
   2166             throw new InvalidObjectException("Cannot read back reference to unshared object");
   2167         }
   2168         return res;
   2169     }
   2170 
   2171     /**
   2172      * Associates a read object with the its serialization handle.
   2173      */
   2174     private void registerObjectRead(Object obj, int handle, boolean unshared) throws IOException {
   2175         if (unshared) {
   2176             obj = UNSHARED_OBJ;
   2177         }
   2178         int index = handle - ObjectStreamConstants.baseWireHandle;
   2179         int size = objectsRead.size();
   2180         // ObjectOutputStream sometimes wastes a handle. I've compared hex dumps of the RI
   2181         // and it seems like that's a 'feature'. Look for calls to objectsWritten.put that
   2182         // are guarded by !unshared tests.
   2183         while (index > size) {
   2184             objectsRead.add(null);
   2185             ++size;
   2186         }
   2187         if (index == size) {
   2188             objectsRead.add(obj);
   2189         } else {
   2190             objectsRead.set(index, obj);
   2191         }
   2192     }
   2193 
   2194     /**
   2195      * Registers a callback for post-deserialization validation of objects. It
   2196      * allows to perform additional consistency checks before the {@code
   2197      * readObject()} method of this class returns its result to the caller. This
   2198      * method can only be called from within the {@code readObject()} method of
   2199      * a class that implements "special" deserialization rules. It can be called
   2200      * multiple times. Validation callbacks are then done in order of decreasing
   2201      * priority, defined by {@code priority}.
   2202      *
   2203      * @param object
   2204      *            an object that can validate itself by receiving a callback.
   2205      * @param priority
   2206      *            the validator's priority.
   2207      * @throws InvalidObjectException
   2208      *             if {@code object} is {@code null}.
   2209      * @throws NotActiveException
   2210      *             if this stream is currently not reading objects. In that
   2211      *             case, calling this method is not allowed.
   2212      * @see ObjectInputValidation#validateObject()
   2213      */
   2214     public synchronized void registerValidation(ObjectInputValidation object,
   2215             int priority) throws NotActiveException, InvalidObjectException {
   2216         // Validation can only be registered when inside readObject calls
   2217         Object instanceBeingRead = this.currentObject;
   2218 
   2219         if (instanceBeingRead == null && nestedLevels == 0) {
   2220             throw new NotActiveException();
   2221         }
   2222         if (object == null) {
   2223             throw new InvalidObjectException("Callback object cannot be null");
   2224         }
   2225         // From now on it is just insertion in a SortedCollection. Since
   2226         // the Java class libraries don't provide that, we have to
   2227         // implement it from scratch here.
   2228         InputValidationDesc desc = new InputValidationDesc();
   2229         desc.validator = object;
   2230         desc.priority = priority;
   2231         // No need for this, validateObject does not take a parameter
   2232         // desc.toValidate = instanceBeingRead;
   2233         if (validations == null) {
   2234             validations = new InputValidationDesc[1];
   2235             validations[0] = desc;
   2236         } else {
   2237             int i = 0;
   2238             for (; i < validations.length; i++) {
   2239                 InputValidationDesc validation = validations[i];
   2240                 // Sorted, higher priority first.
   2241                 if (priority >= validation.priority) {
   2242                     break; // Found the index where to insert
   2243                 }
   2244             }
   2245             InputValidationDesc[] oldValidations = validations;
   2246             int currentSize = oldValidations.length;
   2247             validations = new InputValidationDesc[currentSize + 1];
   2248             System.arraycopy(oldValidations, 0, validations, 0, i);
   2249             System.arraycopy(oldValidations, i, validations, i + 1, currentSize
   2250                     - i);
   2251             validations[i] = desc;
   2252         }
   2253     }
   2254 
   2255     /**
   2256      * Reset the collection of objects already loaded by the receiver.
   2257      */
   2258     private void resetSeenObjects() {
   2259         objectsRead = new ArrayList<Object>();
   2260         nextHandle = baseWireHandle;
   2261         primitiveData = emptyStream;
   2262     }
   2263 
   2264     /**
   2265      * Reset the receiver. The collection of objects already read by the
   2266      * receiver is reset, and internal structures are also reset so that the
   2267      * receiver knows it is in a fresh clean state.
   2268      */
   2269     private void resetState() {
   2270         resetSeenObjects();
   2271         hasPushbackTC = false;
   2272         pushbackTC = 0;
   2273         // nestedLevels = 0;
   2274     }
   2275 
   2276     /**
   2277      * Loads the Java class corresponding to the class descriptor {@code
   2278      * osClass} that has just been read from the source stream.
   2279      *
   2280      * @param osClass
   2281      *            an ObjectStreamClass read from the source stream.
   2282      * @return a Class corresponding to the descriptor {@code osClass}.
   2283      * @throws ClassNotFoundException
   2284      *             if the class for an object cannot be found.
   2285      * @throws IOException
   2286      *             if an I/O error occurs while creating the class.
   2287      * @see ObjectOutputStream#annotateClass(Class)
   2288      */
   2289     protected Class<?> resolveClass(ObjectStreamClass osClass)
   2290             throws IOException, ClassNotFoundException {
   2291         // fastpath: obtain cached value
   2292         Class<?> cls = osClass.forClass();
   2293         if (cls == null) {
   2294             // slowpath: resolve the class
   2295             String className = osClass.getName();
   2296 
   2297             // if it is primitive class, for example, long.class
   2298             cls = PRIMITIVE_CLASSES.get(className);
   2299 
   2300             if (cls == null) {
   2301                 // not primitive class
   2302                 // Use the first non-null ClassLoader on the stack. If null, use
   2303                 // the system class loader
   2304                 cls = Class.forName(className, true, callerClassLoader);
   2305             }
   2306         }
   2307         return cls;
   2308     }
   2309 
   2310     /**
   2311      * Allows trusted subclasses to substitute the specified original {@code
   2312      * object} with a new object. Object substitution has to be activated first
   2313      * with calling {@code enableResolveObject(true)}. This implementation just
   2314      * returns {@code object}.
   2315      *
   2316      * @param object
   2317      *            the original object for which a replacement may be defined.
   2318      * @return the replacement object for {@code object}.
   2319      * @throws IOException
   2320      *             if any I/O error occurs while creating the replacement
   2321      *             object.
   2322      * @see #enableResolveObject
   2323      * @see ObjectOutputStream#enableReplaceObject
   2324      * @see ObjectOutputStream#replaceObject
   2325      */
   2326     protected Object resolveObject(Object object) throws IOException {
   2327         // By default no object replacement. Subclasses can override
   2328         return object;
   2329     }
   2330 
   2331     /**
   2332      * Skips {@code length} bytes on the source stream. This method should not
   2333      * be used to skip bytes at any arbitrary position, just when reading
   2334      * primitive data types (int, char etc).
   2335      *
   2336      * @param length
   2337      *            the number of bytes to skip.
   2338      * @return the number of bytes actually skipped.
   2339      * @throws IOException
   2340      *             if an error occurs while skipping bytes on the source stream.
   2341      * @throws NullPointerException
   2342      *             if the source stream is {@code null}.
   2343      */
   2344     public int skipBytes(int length) throws IOException {
   2345         // To be used with available. Ok to call if reading primitive buffer
   2346         if (input == null) {
   2347             throw new NullPointerException("source stream is null");
   2348         }
   2349 
   2350         int offset = 0;
   2351         while (offset < length) {
   2352             checkReadPrimitiveTypes();
   2353             long skipped = primitiveData.skip(length - offset);
   2354             if (skipped == 0) {
   2355                 return offset;
   2356             }
   2357             offset += (int) skipped;
   2358         }
   2359         return length;
   2360     }
   2361 
   2362     /**
   2363      * Verify if the SUID & the base name for descriptor
   2364      * <code>loadedStreamClass</code>matches
   2365      * the SUID & the base name of the corresponding loaded class and
   2366      * init private fields.
   2367      *
   2368      * @param loadedStreamClass
   2369      *            An ObjectStreamClass that was loaded from the stream.
   2370      *
   2371      * @throws InvalidClassException
   2372      *             If the SUID of the stream class does not match the VM class
   2373      */
   2374     private void verifyAndInit(ObjectStreamClass loadedStreamClass)
   2375             throws InvalidClassException {
   2376 
   2377         Class<?> localClass = loadedStreamClass.forClass();
   2378         ObjectStreamClass localStreamClass = ObjectStreamClass
   2379                 .lookupStreamClass(localClass);
   2380 
   2381         if (loadedStreamClass.getSerialVersionUID() != localStreamClass
   2382                 .getSerialVersionUID()) {
   2383             throw new InvalidClassException(loadedStreamClass.getName(),
   2384                     "Incompatible class (SUID): " + loadedStreamClass +
   2385                             " but expected " + localStreamClass);
   2386         }
   2387 
   2388         String loadedClassBaseName = getBaseName(loadedStreamClass.getName());
   2389         String localClassBaseName = getBaseName(localStreamClass.getName());
   2390 
   2391         if (!loadedClassBaseName.equals(localClassBaseName)) {
   2392             throw new InvalidClassException(loadedStreamClass.getName(),
   2393                     String.format("Incompatible class (base name): %s but expected %s",
   2394                             loadedClassBaseName, localClassBaseName));
   2395         }
   2396 
   2397         loadedStreamClass.initPrivateFields(localStreamClass);
   2398     }
   2399 
   2400     private static String getBaseName(String fullName) {
   2401         int k = fullName.lastIndexOf('.');
   2402 
   2403         if (k == -1 || k == (fullName.length() - 1)) {
   2404             return fullName;
   2405         }
   2406         return fullName.substring(k + 1);
   2407     }
   2408 
   2409     // Avoid recursive defining.
   2410     private static void checkedSetSuperClassDesc(ObjectStreamClass desc,
   2411             ObjectStreamClass superDesc) throws StreamCorruptedException {
   2412         if (desc.equals(superDesc)) {
   2413             throw new StreamCorruptedException();
   2414         }
   2415         desc.setSuperclass(superDesc);
   2416     }
   2417 }
   2418