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.Proxy;
     27 import java.security.PrivilegedAction;
     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             // We may not have been able to find the field, but we still need to read the value
   1093             // and do the other checking, so there's no null check on 'field' here.
   1094             try {
   1095                 Class<?> type = fieldDesc.getTypeInternal();
   1096                 if (type == byte.class) {
   1097                     byte b = input.readByte();
   1098                     if (field != null) {
   1099                         field.setByte(obj, b);
   1100                     }
   1101                 } else if (type == char.class) {
   1102                     char c = input.readChar();
   1103                     if (field != null) {
   1104                         field.setChar(obj, c);
   1105                     }
   1106                 } else if (type == double.class) {
   1107                     double d = input.readDouble();
   1108                     if (field != null) {
   1109                         field.setDouble(obj, d);
   1110                     }
   1111                 } else if (type == float.class) {
   1112                     float f = input.readFloat();
   1113                     if (field != null) {
   1114                         field.setFloat(obj, f);
   1115                     }
   1116                 } else if (type == int.class) {
   1117                     int i = input.readInt();
   1118                     if (field != null) {
   1119                         field.setInt(obj, i);
   1120                     }
   1121                 } else if (type == long.class) {
   1122                     long j = input.readLong();
   1123                     if (field != null) {
   1124                         field.setLong(obj, j);
   1125                     }
   1126                 } else if (type == short.class) {
   1127                     short s = input.readShort();
   1128                     if (field != null) {
   1129                         field.setShort(obj, s);
   1130                     }
   1131                 } else if (type == boolean.class) {
   1132                     boolean z = input.readBoolean();
   1133                     if (field != null) {
   1134                         field.setBoolean(obj, z);
   1135                     }
   1136                 } else {
   1137                     Object toSet = fieldDesc.isUnshared() ? readUnshared() : readObject();
   1138                     if (toSet != null) {
   1139                         // Get the field type from the local field rather than
   1140                         // from the stream's supplied data. That's the field
   1141                         // we'll be setting, so that's the one that needs to be
   1142                         // validated.
   1143                         String fieldName = fieldDesc.getName();
   1144                         ObjectStreamField localFieldDesc = classDesc.getField(fieldName);
   1145                         Class<?> fieldType = localFieldDesc.getTypeInternal();
   1146                         Class<?> valueType = toSet.getClass();
   1147                         if (!fieldType.isAssignableFrom(valueType)) {
   1148                             throw new ClassCastException(classDesc.getName() + "." + fieldName + " - " + fieldType + " not compatible with " + valueType);
   1149                         }
   1150                         if (field != null) {
   1151                             field.set(obj, toSet);
   1152                         }
   1153                     }
   1154                 }
   1155             } catch (IllegalAccessException iae) {
   1156                 // ObjectStreamField should have called setAccessible(true).
   1157                 throw new AssertionError(iae);
   1158             } catch (NoSuchFieldError ignored) {
   1159             }
   1160         }
   1161     }
   1162 
   1163     /**
   1164      * Reads a float (32 bit) from the source stream.
   1165      *
   1166      * @return the float value read from the source stream.
   1167      * @throws EOFException
   1168      *             if the end of the input is reached before the read
   1169      *             request can be satisfied.
   1170      * @throws IOException
   1171      *             if an error occurs while reading from the source stream.
   1172      */
   1173     public float readFloat() throws IOException {
   1174         return primitiveTypes.readFloat();
   1175     }
   1176 
   1177     /**
   1178      * Reads bytes from the source stream into the byte array {@code dst}.
   1179      * This method will block until {@code dst.length} bytes have been read.
   1180      *
   1181      * @param dst
   1182      *            the array in which to store the bytes read.
   1183      * @throws EOFException
   1184      *             if the end of the input is reached before the read
   1185      *             request can be satisfied.
   1186      * @throws IOException
   1187      *             if an error occurs while reading from the source stream.
   1188      */
   1189     public void readFully(byte[] dst) throws IOException {
   1190         primitiveTypes.readFully(dst);
   1191     }
   1192 
   1193     /**
   1194      * Reads {@code byteCount} bytes from the source stream into the byte array {@code dst}.
   1195      *
   1196      * @param dst
   1197      *            the byte array in which to store the bytes read.
   1198      * @param offset
   1199      *            the initial position in {@code dst} to store the bytes
   1200      *            read from the source stream.
   1201      * @param byteCount
   1202      *            the number of bytes to read.
   1203      * @throws EOFException
   1204      *             if the end of the input is reached before the read
   1205      *             request can be satisfied.
   1206      * @throws IOException
   1207      *             if an error occurs while reading from the source stream.
   1208      */
   1209     public void readFully(byte[] dst, int offset, int byteCount) throws IOException {
   1210         primitiveTypes.readFully(dst, offset, byteCount);
   1211     }
   1212 
   1213     /**
   1214      * Walks the hierarchy of classes described by class descriptor
   1215      * {@code classDesc} and reads the field values corresponding to
   1216      * fields declared by the corresponding class descriptor. The instance to
   1217      * store field values into is {@code object}. If the class
   1218      * (corresponding to class descriptor {@code classDesc}) defines
   1219      * private instance method {@code readObject} it will be used to load
   1220      * field values.
   1221      *
   1222      * @param object
   1223      *            Instance into which stored field values loaded.
   1224      * @param classDesc
   1225      *            A class descriptor (an {@code ObjectStreamClass})
   1226      *            defining which fields should be loaded.
   1227      *
   1228      * @throws IOException
   1229      *             If an IO exception happened when reading the field values in
   1230      *             the hierarchy.
   1231      * @throws ClassNotFoundException
   1232      *             If a class for one of the field types could not be found
   1233      * @throws NotActiveException
   1234      *             If {@code defaultReadObject} is called from the wrong
   1235      *             context.
   1236      *
   1237      * @see #defaultReadObject
   1238      * @see #readObject()
   1239      */
   1240     private void readHierarchy(Object object, ObjectStreamClass classDesc)
   1241             throws IOException, ClassNotFoundException, NotActiveException {
   1242         if (object == null && mustResolve) {
   1243             throw new NotActiveException();
   1244         }
   1245 
   1246         List<ObjectStreamClass> streamClassList = classDesc.getHierarchy();
   1247         if (object == null) {
   1248             for (ObjectStreamClass objectStreamClass : streamClassList) {
   1249                 readObjectForClass(null, objectStreamClass);
   1250             }
   1251         } else {
   1252             List<Class<?>> superclasses = cachedSuperclasses.get(object.getClass());
   1253             if (superclasses == null) {
   1254                 superclasses = cacheSuperclassesFor(object.getClass());
   1255             }
   1256 
   1257             int lastIndex = 0;
   1258             for (int i = 0, end = superclasses.size(); i < end; ++i) {
   1259                 Class<?> superclass = superclasses.get(i);
   1260                 int index = findStreamSuperclass(superclass, streamClassList, lastIndex);
   1261                 if (index == -1) {
   1262                     readObjectNoData(object, superclass,
   1263                             ObjectStreamClass.lookupStreamClass(superclass));
   1264                 } else {
   1265                     for (int j = lastIndex; j <= index; j++) {
   1266                         readObjectForClass(object, streamClassList.get(j));
   1267                     }
   1268                     lastIndex = index + 1;
   1269                 }
   1270             }
   1271         }
   1272     }
   1273 
   1274     private HashMap<Class<?>, List<Class<?>>> cachedSuperclasses = new HashMap<Class<?>, List<Class<?>>>();
   1275 
   1276     private List<Class<?>> cacheSuperclassesFor(Class<?> c) {
   1277         ArrayList<Class<?>> result = new ArrayList<Class<?>>();
   1278         Class<?> nextClass = c;
   1279         while (nextClass != null) {
   1280             Class<?> testClass = nextClass.getSuperclass();
   1281             if (testClass != null) {
   1282                 result.add(0, nextClass);
   1283             }
   1284             nextClass = testClass;
   1285         }
   1286         cachedSuperclasses.put(c, result);
   1287         return result;
   1288     }
   1289 
   1290     private int findStreamSuperclass(Class<?> cl, List<ObjectStreamClass> classList, int lastIndex) {
   1291         for (int i = lastIndex, end = classList.size(); i < end; i++) {
   1292             ObjectStreamClass objCl = classList.get(i);
   1293             String forName = objCl.forClass().getName();
   1294 
   1295             if (objCl.getName().equals(forName)) {
   1296                 if (cl.getName().equals(objCl.getName())) {
   1297                     return i;
   1298                 }
   1299             } else {
   1300                 // there was a class replacement
   1301                 if (cl.getName().equals(forName)) {
   1302                     return i;
   1303                 }
   1304             }
   1305         }
   1306         return -1;
   1307     }
   1308 
   1309     private void readObjectNoData(Object object, Class<?> cl, ObjectStreamClass classDesc)
   1310             throws ObjectStreamException {
   1311         if (!classDesc.isSerializable()) {
   1312             return;
   1313         }
   1314         if (classDesc.hasMethodReadObjectNoData()){
   1315             final Method readMethod = classDesc.getMethodReadObjectNoData();
   1316             try {
   1317                 readMethod.invoke(object);
   1318             } catch (InvocationTargetException e) {
   1319                 Throwable ex = e.getTargetException();
   1320                 if (ex instanceof RuntimeException) {
   1321                     throw (RuntimeException) ex;
   1322                 } else if (ex instanceof Error) {
   1323                     throw (Error) ex;
   1324                 }
   1325                 throw (ObjectStreamException) ex;
   1326             } catch (IllegalAccessException e) {
   1327                 throw new RuntimeException(e.toString());
   1328             }
   1329         }
   1330 
   1331     }
   1332 
   1333     private void readObjectForClass(Object object, ObjectStreamClass classDesc)
   1334             throws IOException, ClassNotFoundException, NotActiveException {
   1335         // Have to do this before calling defaultReadObject or anything that
   1336         // calls defaultReadObject
   1337         currentObject = object;
   1338         currentClass = classDesc;
   1339 
   1340         boolean hadWriteMethod = (classDesc.getFlags() & SC_WRITE_METHOD) != 0;
   1341         Class<?> targetClass = classDesc.forClass();
   1342 
   1343         final Method readMethod;
   1344         if (targetClass == null || !mustResolve) {
   1345             readMethod = null;
   1346         } else {
   1347             readMethod = classDesc.getMethodReadObject();
   1348         }
   1349         try {
   1350             if (readMethod != null) {
   1351                 // We have to be able to fetch its value, even if it is private
   1352                 readMethod.setAccessible(true);
   1353                 try {
   1354                     readMethod.invoke(object, this);
   1355                 } catch (InvocationTargetException e) {
   1356                     Throwable ex = e.getTargetException();
   1357                     if (ex instanceof ClassNotFoundException) {
   1358                         throw (ClassNotFoundException) ex;
   1359                     } else if (ex instanceof RuntimeException) {
   1360                         throw (RuntimeException) ex;
   1361                     } else if (ex instanceof Error) {
   1362                         throw (Error) ex;
   1363                     }
   1364                     throw (IOException) ex;
   1365                 } catch (IllegalAccessException e) {
   1366                     throw new RuntimeException(e.toString());
   1367                 }
   1368             } else {
   1369                 defaultReadObject();
   1370             }
   1371             if (hadWriteMethod) {
   1372                 discardData();
   1373             }
   1374         } finally {
   1375             // Cleanup, needs to run always so that we can later detect invalid
   1376             // calls to defaultReadObject
   1377             currentObject = null; // We did not set this, so we do not need to
   1378             // clean it
   1379             currentClass = null;
   1380         }
   1381     }
   1382 
   1383     /**
   1384      * Reads an integer (32 bit) from the source stream.
   1385      *
   1386      * @return the integer value read from the source stream.
   1387      * @throws EOFException
   1388      *             if the end of the input is reached before the read
   1389      *             request can be satisfied.
   1390      * @throws IOException
   1391      *             if an error occurs while reading from the source stream.
   1392      */
   1393     public int readInt() throws IOException {
   1394         return primitiveTypes.readInt();
   1395     }
   1396 
   1397     /**
   1398      * Reads the next line from the source stream. Lines are terminated by
   1399      * {@code '\r'}, {@code '\n'}, {@code "\r\n"} or an {@code EOF}.
   1400      *
   1401      * @return the string read from the source stream.
   1402      * @throws IOException
   1403      *             if an error occurs while reading from the source stream.
   1404      * @deprecated Use {@link BufferedReader}
   1405      */
   1406     @Deprecated
   1407     public String readLine() throws IOException {
   1408         return primitiveTypes.readLine();
   1409     }
   1410 
   1411     /**
   1412      * Reads a long (64 bit) from the source stream.
   1413      *
   1414      * @return the long value read from the source stream.
   1415      * @throws EOFException
   1416      *             if the end of the input is reached before the read
   1417      *             request can be satisfied.
   1418      * @throws IOException
   1419      *             if an error occurs while reading from the source stream.
   1420      */
   1421     public long readLong() throws IOException {
   1422         return primitiveTypes.readLong();
   1423     }
   1424 
   1425     /**
   1426      * Read a new array from the receiver. It is assumed the array has not been
   1427      * read yet (not a cyclic reference). Return the array read.
   1428      *
   1429      * @param unshared
   1430      *            read the object unshared
   1431      * @return the array read
   1432      *
   1433      * @throws IOException
   1434      *             If an IO exception happened when reading the array.
   1435      * @throws ClassNotFoundException
   1436      *             If a class for one of the objects could not be found
   1437      * @throws OptionalDataException
   1438      *             If optional data could not be found when reading the array.
   1439      */
   1440     private Object readNewArray(boolean unshared) throws OptionalDataException,
   1441             ClassNotFoundException, IOException {
   1442         ObjectStreamClass classDesc = readClassDesc();
   1443 
   1444         if (classDesc == null) {
   1445             throw missingClassDescriptor();
   1446         }
   1447 
   1448         int newHandle = nextHandle();
   1449 
   1450         // Array size
   1451         int size = input.readInt();
   1452         Class<?> arrayClass = classDesc.forClass();
   1453         Class<?> componentType = arrayClass.getComponentType();
   1454         Object result = Array.newInstance(componentType, size);
   1455 
   1456         registerObjectRead(result, newHandle, unshared);
   1457 
   1458         // Now we have code duplication just because Java is typed. We have to
   1459         // read N elements and assign to array positions, but we must typecast
   1460         // the array first, and also call different methods depending on the
   1461         // elements.
   1462         if (componentType.isPrimitive()) {
   1463             if (componentType == int.class) {
   1464                 int[] intArray = (int[]) result;
   1465                 for (int i = 0; i < size; i++) {
   1466                     intArray[i] = input.readInt();
   1467                 }
   1468             } else if (componentType == byte.class) {
   1469                 byte[] byteArray = (byte[]) result;
   1470                 input.readFully(byteArray, 0, size);
   1471             } else if (componentType == char.class) {
   1472                 char[] charArray = (char[]) result;
   1473                 for (int i = 0; i < size; i++) {
   1474                     charArray[i] = input.readChar();
   1475                 }
   1476             } else if (componentType == short.class) {
   1477                 short[] shortArray = (short[]) result;
   1478                 for (int i = 0; i < size; i++) {
   1479                     shortArray[i] = input.readShort();
   1480                 }
   1481             } else if (componentType == boolean.class) {
   1482                 boolean[] booleanArray = (boolean[]) result;
   1483                 for (int i = 0; i < size; i++) {
   1484                     booleanArray[i] = input.readBoolean();
   1485                 }
   1486             } else if (componentType == long.class) {
   1487                 long[] longArray = (long[]) result;
   1488                 for (int i = 0; i < size; i++) {
   1489                     longArray[i] = input.readLong();
   1490                 }
   1491             } else if (componentType == float.class) {
   1492                 float[] floatArray = (float[]) result;
   1493                 for (int i = 0; i < size; i++) {
   1494                     floatArray[i] = input.readFloat();
   1495                 }
   1496             } else if (componentType == double.class) {
   1497                 double[] doubleArray = (double[]) result;
   1498                 for (int i = 0; i < size; i++) {
   1499                     doubleArray[i] = input.readDouble();
   1500                 }
   1501             } else {
   1502                 throw new ClassNotFoundException("Wrong base type in " + classDesc.getName());
   1503             }
   1504         } else {
   1505             // Array of Objects
   1506             Object[] objectArray = (Object[]) result;
   1507             for (int i = 0; i < size; i++) {
   1508                 // TODO: This place is the opportunity for enhancement
   1509                 //      We can implement writing elements through fast-path,
   1510                 //      without setting up the context (see readObject()) for
   1511                 //      each element with public API
   1512                 objectArray[i] = readObject();
   1513             }
   1514         }
   1515         if (enableResolve) {
   1516             result = resolveObject(result);
   1517             registerObjectRead(result, newHandle, false);
   1518         }
   1519         return result;
   1520     }
   1521 
   1522     /**
   1523      * Reads a new class from the receiver. It is assumed the class has not been
   1524      * read yet (not a cyclic reference). Return the class read.
   1525      *
   1526      * @param unshared
   1527      *            read the object unshared
   1528      * @return The {@code java.lang.Class} read from the stream.
   1529      *
   1530      * @throws IOException
   1531      *             If an IO exception happened when reading the class.
   1532      * @throws ClassNotFoundException
   1533      *             If a class for one of the objects could not be found
   1534      */
   1535     private Class<?> readNewClass(boolean unshared) throws ClassNotFoundException, IOException {
   1536         ObjectStreamClass classDesc = readClassDesc();
   1537         if (classDesc == null) {
   1538             throw missingClassDescriptor();
   1539         }
   1540         Class<?> localClass = classDesc.forClass();
   1541         if (localClass != null) {
   1542             registerObjectRead(localClass, nextHandle(), unshared);
   1543         }
   1544         return localClass;
   1545     }
   1546 
   1547     /*
   1548      * read class type for Enum, note there's difference between enum and normal
   1549      * classes
   1550      */
   1551     private ObjectStreamClass readEnumDesc() throws IOException,
   1552             ClassNotFoundException {
   1553         byte tc = nextTC();
   1554         switch (tc) {
   1555             case TC_CLASSDESC:
   1556                 return readEnumDescInternal();
   1557             case TC_REFERENCE:
   1558                 return (ObjectStreamClass) readCyclicReference();
   1559             case TC_NULL:
   1560                 return null;
   1561             default:
   1562                 throw corruptStream(tc);
   1563         }
   1564     }
   1565 
   1566     private ObjectStreamClass readEnumDescInternal() throws IOException, ClassNotFoundException {
   1567         ObjectStreamClass classDesc;
   1568         primitiveData = input;
   1569         int oldHandle = descriptorHandle;
   1570         descriptorHandle = nextHandle();
   1571         classDesc = readClassDescriptor();
   1572         registerObjectRead(classDesc, descriptorHandle, false);
   1573         descriptorHandle = oldHandle;
   1574         primitiveData = emptyStream;
   1575         classDesc.setClass(resolveClass(classDesc));
   1576         // Consume unread class annotation data and TC_ENDBLOCKDATA
   1577         discardData();
   1578         ObjectStreamClass superClass = readClassDesc();
   1579         checkedSetSuperClassDesc(classDesc, superClass);
   1580         // Check SUIDs, note all SUID for Enum is 0L
   1581         if (0L != classDesc.getSerialVersionUID() || 0L != superClass.getSerialVersionUID()) {
   1582             throw new InvalidClassException(superClass.getName(),
   1583                     "Incompatible class (SUID): " + superClass + " but expected " + superClass);
   1584         }
   1585         byte tc = nextTC();
   1586         // discard TC_ENDBLOCKDATA after classDesc if any
   1587         if (tc == TC_ENDBLOCKDATA) {
   1588             // read next parent class. For enum, it may be null
   1589             superClass.setSuperclass(readClassDesc());
   1590         } else {
   1591             // not TC_ENDBLOCKDATA, push back for next read
   1592             pushbackTC();
   1593         }
   1594         return classDesc;
   1595     }
   1596 
   1597     @SuppressWarnings("unchecked")// For the Enum.valueOf call
   1598     private Object readEnum(boolean unshared) throws OptionalDataException,
   1599             ClassNotFoundException, IOException {
   1600         // read classdesc for Enum first
   1601         ObjectStreamClass classDesc = readEnumDesc();
   1602         int newHandle = nextHandle();
   1603         // read name after class desc
   1604         String name;
   1605         byte tc = nextTC();
   1606         switch (tc) {
   1607             case TC_REFERENCE:
   1608                 if (unshared) {
   1609                     readNewHandle();
   1610                     throw new InvalidObjectException("Unshared read of back reference");
   1611                 }
   1612                 name = (String) readCyclicReference();
   1613                 break;
   1614             case TC_STRING:
   1615                 name = (String) readNewString(unshared);
   1616                 break;
   1617             default:
   1618                 throw corruptStream(tc);
   1619         }
   1620 
   1621         Enum<?> result;
   1622         try {
   1623             result = Enum.valueOf((Class) classDesc.forClass(), name);
   1624         } catch (IllegalArgumentException e) {
   1625             throw new InvalidObjectException(e.getMessage());
   1626         }
   1627         registerObjectRead(result, newHandle, unshared);
   1628         return result;
   1629     }
   1630 
   1631     /**
   1632      * Reads a new class descriptor from the receiver. It is assumed the class
   1633      * descriptor has not been read yet (not a cyclic reference). Return the
   1634      * class descriptor read.
   1635      *
   1636      * @param unshared
   1637      *            read the object unshared
   1638      * @return The {@code ObjectStreamClass} read from the stream.
   1639      *
   1640      * @throws IOException
   1641      *             If an IO exception happened when reading the class
   1642      *             descriptor.
   1643      * @throws ClassNotFoundException
   1644      *             If a class for one of the objects could not be found
   1645      */
   1646     private ObjectStreamClass readNewClassDesc(boolean unshared)
   1647             throws ClassNotFoundException, IOException {
   1648         // So read...() methods can be used by
   1649         // subclasses during readClassDescriptor()
   1650         primitiveData = input;
   1651         int oldHandle = descriptorHandle;
   1652         descriptorHandle = nextHandle();
   1653         ObjectStreamClass newClassDesc = readClassDescriptor();
   1654         registerObjectRead(newClassDesc, descriptorHandle, unshared);
   1655         descriptorHandle = oldHandle;
   1656         primitiveData = emptyStream;
   1657 
   1658         // We need to map classDesc to class.
   1659         try {
   1660             newClassDesc.setClass(resolveClass(newClassDesc));
   1661             // Check SUIDs & base name of the class
   1662             verifyAndInit(newClassDesc);
   1663         } catch (ClassNotFoundException e) {
   1664             if (mustResolve) {
   1665                 throw e;
   1666                 // Just continue, the class may not be required
   1667             }
   1668         }
   1669 
   1670         // Resolve the field signatures using the class loader of the
   1671         // resolved class
   1672         ObjectStreamField[] fields = newClassDesc.getLoadFields();
   1673         fields = (fields == null) ? ObjectStreamClass.NO_FIELDS : fields;
   1674         ClassLoader loader = newClassDesc.forClass() == null ? callerClassLoader
   1675                 : newClassDesc.forClass().getClassLoader();
   1676         for (ObjectStreamField element : fields) {
   1677             element.resolve(loader);
   1678         }
   1679 
   1680         // Consume unread class annotation data and TC_ENDBLOCKDATA
   1681         discardData();
   1682         checkedSetSuperClassDesc(newClassDesc, readClassDesc());
   1683         return newClassDesc;
   1684     }
   1685 
   1686     /**
   1687      * Reads a new proxy class descriptor from the receiver. It is assumed the
   1688      * proxy class descriptor has not been read yet (not a cyclic reference).
   1689      * Return the proxy class descriptor read.
   1690      *
   1691      * @return The {@code Class} read from the stream.
   1692      *
   1693      * @throws IOException
   1694      *             If an IO exception happened when reading the class
   1695      *             descriptor.
   1696      * @throws ClassNotFoundException
   1697      *             If a class for one of the objects could not be found
   1698      */
   1699     private Class<?> readNewProxyClassDesc() throws ClassNotFoundException,
   1700             IOException {
   1701         int count = input.readInt();
   1702         String[] interfaceNames = new String[count];
   1703         for (int i = 0; i < count; i++) {
   1704             interfaceNames[i] = input.readUTF();
   1705         }
   1706         Class<?> proxy = resolveProxyClass(interfaceNames);
   1707         // Consume unread class annotation data and TC_ENDBLOCKDATA
   1708         discardData();
   1709         return proxy;
   1710     }
   1711 
   1712     /**
   1713      * Reads a class descriptor from the source stream.
   1714      *
   1715      * @return the class descriptor read from the source stream.
   1716      * @throws ClassNotFoundException
   1717      *             if a class for one of the objects cannot be found.
   1718      * @throws IOException
   1719      *             if an error occurs while reading from the source stream.
   1720      */
   1721     protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException {
   1722         ObjectStreamClass newClassDesc = new ObjectStreamClass();
   1723         String name = input.readUTF();
   1724         if (name.length() == 0) {
   1725             throw new IOException("The stream is corrupted");
   1726         }
   1727         newClassDesc.setName(name);
   1728         newClassDesc.setSerialVersionUID(input.readLong());
   1729         newClassDesc.setFlags(input.readByte());
   1730 
   1731         /*
   1732          * We must register the class descriptor before reading field
   1733          * descriptors. If called outside of readObject, the descriptorHandle
   1734          * might be unset.
   1735          */
   1736         if (descriptorHandle == -1) {
   1737             descriptorHandle = nextHandle();
   1738         }
   1739         registerObjectRead(newClassDesc, descriptorHandle, false);
   1740 
   1741         readFieldDescriptors(newClassDesc);
   1742         return newClassDesc;
   1743     }
   1744 
   1745     /**
   1746      * Creates the proxy class that implements the interfaces specified in
   1747      * {@code interfaceNames}.
   1748      *
   1749      * @param interfaceNames
   1750      *            the interfaces used to create the proxy class.
   1751      * @return the proxy class.
   1752      * @throws ClassNotFoundException
   1753      *             if the proxy class or any of the specified interfaces cannot
   1754      *             be created.
   1755      * @throws IOException
   1756      *             if an error occurs while reading from the source stream.
   1757      * @see ObjectOutputStream#annotateProxyClass(Class)
   1758      */
   1759     protected Class<?> resolveProxyClass(String[] interfaceNames)
   1760             throws IOException, ClassNotFoundException {
   1761         // TODO: This method is opportunity for performance enhancement
   1762         //       We can cache the classloader and recently used interfaces.
   1763         ClassLoader loader = ClassLoader.getSystemClassLoader();
   1764         Class<?>[] interfaces = new Class<?>[interfaceNames.length];
   1765         for (int i = 0; i < interfaceNames.length; i++) {
   1766             interfaces[i] = Class.forName(interfaceNames[i], false, loader);
   1767         }
   1768         try {
   1769             return Proxy.getProxyClass(loader, interfaces);
   1770         } catch (IllegalArgumentException e) {
   1771             throw new ClassNotFoundException(e.toString(), e);
   1772         }
   1773     }
   1774 
   1775     private int readNewHandle() throws IOException {
   1776         return input.readInt();
   1777     }
   1778 
   1779     /**
   1780      * Read a new object from the stream. It is assumed the object has not been
   1781      * loaded yet (not a cyclic reference). Return the object read.
   1782      *
   1783      * If the object implements <code>Externalizable</code> its
   1784      * <code>readExternal</code> is called. Otherwise, all fields described by
   1785      * the class hierarchy are loaded. Each class can define how its declared
   1786      * instance fields are loaded by defining a private method
   1787      * <code>readObject</code>
   1788      *
   1789      * @param unshared
   1790      *            read the object unshared
   1791      * @return the object read
   1792      *
   1793      * @throws IOException
   1794      *             If an IO exception happened when reading the object.
   1795      * @throws OptionalDataException
   1796      *             If optional data could not be found when reading the object
   1797      *             graph
   1798      * @throws ClassNotFoundException
   1799      *             If a class for one of the objects could not be found
   1800      */
   1801     private Object readNewObject(boolean unshared)
   1802             throws OptionalDataException, ClassNotFoundException, IOException {
   1803         ObjectStreamClass classDesc = readClassDesc();
   1804 
   1805         if (classDesc == null) {
   1806             throw missingClassDescriptor();
   1807         }
   1808 
   1809         int newHandle = nextHandle();
   1810         Class<?> objectClass = classDesc.forClass();
   1811         Object result = null;
   1812         Object registeredResult = null;
   1813         if (objectClass != null) {
   1814             // Now we know which class to instantiate and which constructor to
   1815             // run. We are allowed to run the constructor.
   1816             result = classDesc.newInstance(objectClass);
   1817             registerObjectRead(result, newHandle, unshared);
   1818             registeredResult = result;
   1819         } else {
   1820             result = null;
   1821         }
   1822 
   1823         try {
   1824             // This is how we know what to do in defaultReadObject. And it is
   1825             // also used by defaultReadObject to check if it was called from an
   1826             // invalid place. It also allows readExternal to call
   1827             // defaultReadObject and have it work.
   1828             currentObject = result;
   1829             currentClass = classDesc;
   1830 
   1831             // If Externalizable, just let the object read itself
   1832             // Note that this value comes from the Stream, and in fact it could be
   1833             // that the classes have been changed so that the info below now
   1834             // conflicts with the newer class
   1835             boolean wasExternalizable = (classDesc.getFlags() & SC_EXTERNALIZABLE) != 0;
   1836             if (wasExternalizable) {
   1837                 boolean blockData = (classDesc.getFlags() & SC_BLOCK_DATA) != 0;
   1838                 if (!blockData) {
   1839                     primitiveData = input;
   1840                 }
   1841                 if (mustResolve) {
   1842                     Externalizable extern = (Externalizable) result;
   1843                     extern.readExternal(this);
   1844                 }
   1845                 if (blockData) {
   1846                     // Similar to readHierarchy. Anything not read by
   1847                     // readExternal has to be consumed here
   1848                     discardData();
   1849                 } else {
   1850                     primitiveData = emptyStream;
   1851                 }
   1852             } else {
   1853                 // If we got here, it is Serializable but not Externalizable.
   1854                 // Walk the hierarchy reading each class' slots
   1855                 readHierarchy(result, classDesc);
   1856             }
   1857         } finally {
   1858             // Cleanup, needs to run always so that we can later detect invalid
   1859             // calls to defaultReadObject
   1860             currentObject = null;
   1861             currentClass = null;
   1862         }
   1863 
   1864         if (objectClass != null) {
   1865 
   1866             if (classDesc.hasMethodReadResolve()){
   1867                 Method methodReadResolve = classDesc.getMethodReadResolve();
   1868                 try {
   1869                     result = methodReadResolve.invoke(result, (Object[]) null);
   1870                 } catch (IllegalAccessException ignored) {
   1871                 } catch (InvocationTargetException ite) {
   1872                     Throwable target = ite.getTargetException();
   1873                     if (target instanceof ObjectStreamException) {
   1874                         throw (ObjectStreamException) target;
   1875                     } else if (target instanceof Error) {
   1876                         throw (Error) target;
   1877                     } else {
   1878                         throw (RuntimeException) target;
   1879                     }
   1880                 }
   1881 
   1882             }
   1883         }
   1884         // We get here either if class-based replacement was not needed or if it
   1885         // was needed but produced the same object or if it could not be
   1886         // computed.
   1887 
   1888         // The object to return is the one we instantiated or a replacement for
   1889         // it
   1890         if (result != null && enableResolve) {
   1891             result = resolveObject(result);
   1892         }
   1893         if (registeredResult != result) {
   1894             registerObjectRead(result, newHandle, unshared);
   1895         }
   1896         return result;
   1897     }
   1898 
   1899     private InvalidClassException missingClassDescriptor() throws InvalidClassException {
   1900         throw new InvalidClassException("Read null attempting to read class descriptor for object");
   1901     }
   1902 
   1903     /**
   1904      * Read a string encoded in {@link DataInput modified UTF-8} from the
   1905      * receiver. Return the string read.
   1906      *
   1907      * @param unshared
   1908      *            read the object unshared
   1909      * @return the string just read.
   1910      * @throws IOException
   1911      *             If an IO exception happened when reading the String.
   1912      */
   1913     private Object readNewString(boolean unshared) throws IOException {
   1914         Object result = input.readUTF();
   1915         if (enableResolve) {
   1916             result = resolveObject(result);
   1917         }
   1918         registerObjectRead(result, nextHandle(), unshared);
   1919 
   1920         return result;
   1921     }
   1922 
   1923     /**
   1924      * Read a new String in UTF format from the receiver. Return the string
   1925      * read.
   1926      *
   1927      * @param unshared
   1928      *            read the object unshared
   1929      * @return the string just read.
   1930      *
   1931      * @throws IOException
   1932      *             If an IO exception happened when reading the String.
   1933      */
   1934     private Object readNewLongString(boolean unshared) throws IOException {
   1935         long length = input.readLong();
   1936         Object result = input.decodeUTF((int) length);
   1937         if (enableResolve) {
   1938             result = resolveObject(result);
   1939         }
   1940         registerObjectRead(result, nextHandle(), unshared);
   1941 
   1942         return result;
   1943     }
   1944 
   1945     /**
   1946      * Reads the next object from the source stream.
   1947      *
   1948      * @return the object read from the source stream.
   1949      * @throws ClassNotFoundException
   1950      *             if the class of one of the objects in the object graph cannot
   1951      *             be found.
   1952      * @throws IOException
   1953      *             if an error occurs while reading from the source stream.
   1954      * @throws OptionalDataException
   1955      *             if primitive data types were found instead of an object.
   1956      * @see ObjectOutputStream#writeObject(Object)
   1957      */
   1958     public final Object readObject() throws OptionalDataException,
   1959             ClassNotFoundException, IOException {
   1960         return readObject(false);
   1961     }
   1962 
   1963     /**
   1964      * Reads the next unshared object from the source stream.
   1965      *
   1966      * @return the new object read.
   1967      * @throws ClassNotFoundException
   1968      *             if the class of one of the objects in the object graph cannot
   1969      *             be found.
   1970      * @throws IOException
   1971      *             if an error occurs while reading from the source stream.
   1972      * @see ObjectOutputStream#writeUnshared
   1973      */
   1974     public Object readUnshared() throws IOException, ClassNotFoundException {
   1975         return readObject(true);
   1976     }
   1977 
   1978     private Object readObject(boolean unshared) throws OptionalDataException,
   1979             ClassNotFoundException, IOException {
   1980         boolean restoreInput = (primitiveData == input);
   1981         if (restoreInput) {
   1982             primitiveData = emptyStream;
   1983         }
   1984 
   1985         // This is the spec'ed behavior in JDK 1.2. Very bizarre way to allow
   1986         // behavior overriding.
   1987         if (subclassOverridingImplementation && !unshared) {
   1988             return readObjectOverride();
   1989         }
   1990 
   1991         // If we still had primitive types to read, should we discard them
   1992         // (reset the primitiveTypes stream) or leave as is, so that attempts to
   1993         // read primitive types won't read 'past data' ???
   1994         Object result;
   1995         try {
   1996             // We need this so we can tell when we are returning to the
   1997             // original/outside caller
   1998             if (++nestedLevels == 1) {
   1999                 // Remember the caller's class loader
   2000                 callerClassLoader = getClosestUserClassLoader();
   2001             }
   2002 
   2003             result = readNonPrimitiveContent(unshared);
   2004             if (restoreInput) {
   2005                 primitiveData = input;
   2006             }
   2007         } finally {
   2008             // We need this so we can tell when we are returning to the
   2009             // original/outside caller
   2010             if (--nestedLevels == 0) {
   2011                 // We are going to return to the original caller, perform
   2012                 // cleanups.
   2013                 // No more need to remember the caller's class loader
   2014                 callerClassLoader = null;
   2015             }
   2016         }
   2017 
   2018         // Done reading this object. Is it time to return to the original
   2019         // caller? If so we need to perform validations first.
   2020         if (nestedLevels == 0 && validations != null) {
   2021             // We are going to return to the original caller. If validation is
   2022             // enabled we need to run them now and then cleanup the validation
   2023             // collection
   2024             try {
   2025                 for (InputValidationDesc element : validations) {
   2026                     element.validator.validateObject();
   2027                 }
   2028             } finally {
   2029                 // Validations have to be renewed, since they are only called
   2030                 // from readObject
   2031                 validations = null;
   2032             }
   2033         }
   2034         return result;
   2035     }
   2036 
   2037     private static final ClassLoader bootstrapLoader = Object.class.getClassLoader();
   2038     private static final ClassLoader systemLoader = ClassLoader.getSystemClassLoader();
   2039 
   2040     /**
   2041      * Searches up the call stack to find the closest user-defined class loader.
   2042      *
   2043      * @return a user-defined class loader or null if one isn't found
   2044      */
   2045     private static ClassLoader getClosestUserClassLoader() {
   2046         Class<?>[] stackClasses = VMStack.getClasses(-1);
   2047         for (Class<?> stackClass : stackClasses) {
   2048             ClassLoader loader = stackClass.getClassLoader();
   2049             if (loader != null && loader != bootstrapLoader
   2050                     && loader != systemLoader) {
   2051                 return loader;
   2052             }
   2053         }
   2054         return null;
   2055     }
   2056 
   2057     /**
   2058      * Method to be overridden by subclasses to read the next object from the
   2059      * source stream.
   2060      *
   2061      * @return the object read from the source stream.
   2062      * @throws ClassNotFoundException
   2063      *             if the class of one of the objects in the object graph cannot
   2064      *             be found.
   2065      * @throws IOException
   2066      *             if an error occurs while reading from the source stream.
   2067      * @throws OptionalDataException
   2068      *             if primitive data types were found instead of an object.
   2069      * @see ObjectOutputStream#writeObjectOverride
   2070      */
   2071     protected Object readObjectOverride() throws OptionalDataException,
   2072             ClassNotFoundException, IOException {
   2073         if (input == null) {
   2074             return null;
   2075         }
   2076         // Subclasses must override.
   2077         throw new IOException();
   2078     }
   2079 
   2080     /**
   2081      * Reads a short (16 bit) from the source stream.
   2082      *
   2083      * @return the short value read from the source stream.
   2084      * @throws IOException
   2085      *             if an error occurs while reading from the source stream.
   2086      */
   2087     public short readShort() throws IOException {
   2088         return primitiveTypes.readShort();
   2089     }
   2090 
   2091     /**
   2092      * Reads and validates the ObjectInputStream header from the source stream.
   2093      *
   2094      * @throws IOException
   2095      *             if an error occurs while reading from the source stream.
   2096      * @throws StreamCorruptedException
   2097      *             if the source stream does not contain readable serialized
   2098      *             objects.
   2099      */
   2100     protected void readStreamHeader() throws IOException,
   2101             StreamCorruptedException {
   2102         if (input.readShort() == STREAM_MAGIC
   2103                 && input.readShort() == STREAM_VERSION) {
   2104             return;
   2105         }
   2106         throw new StreamCorruptedException();
   2107     }
   2108 
   2109     /**
   2110      * Reads an unsigned byte (8 bit) from the source stream.
   2111      *
   2112      * @return the unsigned byte value read from the source stream packaged in
   2113      *         an integer.
   2114      * @throws EOFException
   2115      *             if the end of the input is reached before the read
   2116      *             request can be satisfied.
   2117      * @throws IOException
   2118      *             if an error occurs while reading from the source stream.
   2119      */
   2120     public int readUnsignedByte() throws IOException {
   2121         return primitiveTypes.readUnsignedByte();
   2122     }
   2123 
   2124     /**
   2125      * Reads an unsigned short (16 bit) from the source stream.
   2126      *
   2127      * @return the unsigned short value read from the source stream packaged in
   2128      *         an integer.
   2129      * @throws EOFException
   2130      *             if the end of the input is reached before the read
   2131      *             request can be satisfied.
   2132      * @throws IOException
   2133      *             if an error occurs while reading from the source stream.
   2134      */
   2135     public int readUnsignedShort() throws IOException {
   2136         return primitiveTypes.readUnsignedShort();
   2137     }
   2138 
   2139     /**
   2140      * Reads a string encoded in {@link DataInput modified UTF-8} from the
   2141      * source stream.
   2142      *
   2143      * @return the string encoded in {@link DataInput modified UTF-8} read from
   2144      *         the source stream.
   2145      * @throws EOFException
   2146      *             if the end of the input is reached before the read
   2147      *             request can be satisfied.
   2148      * @throws IOException
   2149      *             if an error occurs while reading from the source stream.
   2150      */
   2151     public String readUTF() throws IOException {
   2152         return primitiveTypes.readUTF();
   2153     }
   2154 
   2155     /**
   2156      * Returns the previously-read object corresponding to the given serialization handle.
   2157      * @throws InvalidObjectException
   2158      *             If there is no previously-read object with this handle
   2159      */
   2160     private Object registeredObjectRead(int handle) throws InvalidObjectException {
   2161         Object res = objectsRead.get(handle - ObjectStreamConstants.baseWireHandle);
   2162         if (res == UNSHARED_OBJ) {
   2163             throw new InvalidObjectException("Cannot read back reference to unshared object");
   2164         }
   2165         return res;
   2166     }
   2167 
   2168     /**
   2169      * Associates a read object with the its serialization handle.
   2170      */
   2171     private void registerObjectRead(Object obj, int handle, boolean unshared) throws IOException {
   2172         if (unshared) {
   2173             obj = UNSHARED_OBJ;
   2174         }
   2175         int index = handle - ObjectStreamConstants.baseWireHandle;
   2176         int size = objectsRead.size();
   2177         // ObjectOutputStream sometimes wastes a handle. I've compared hex dumps of the RI
   2178         // and it seems like that's a 'feature'. Look for calls to objectsWritten.put that
   2179         // are guarded by !unshared tests.
   2180         while (index > size) {
   2181             objectsRead.add(null);
   2182             ++size;
   2183         }
   2184         if (index == size) {
   2185             objectsRead.add(obj);
   2186         } else {
   2187             objectsRead.set(index, obj);
   2188         }
   2189     }
   2190 
   2191     /**
   2192      * Registers a callback for post-deserialization validation of objects. It
   2193      * allows to perform additional consistency checks before the {@code
   2194      * readObject()} method of this class returns its result to the caller. This
   2195      * method can only be called from within the {@code readObject()} method of
   2196      * a class that implements "special" deserialization rules. It can be called
   2197      * multiple times. Validation callbacks are then done in order of decreasing
   2198      * priority, defined by {@code priority}.
   2199      *
   2200      * @param object
   2201      *            an object that can validate itself by receiving a callback.
   2202      * @param priority
   2203      *            the validator's priority.
   2204      * @throws InvalidObjectException
   2205      *             if {@code object} is {@code null}.
   2206      * @throws NotActiveException
   2207      *             if this stream is currently not reading objects. In that
   2208      *             case, calling this method is not allowed.
   2209      * @see ObjectInputValidation#validateObject()
   2210      */
   2211     public synchronized void registerValidation(ObjectInputValidation object,
   2212             int priority) throws NotActiveException, InvalidObjectException {
   2213         // Validation can only be registered when inside readObject calls
   2214         Object instanceBeingRead = this.currentObject;
   2215 
   2216         if (instanceBeingRead == null && nestedLevels == 0) {
   2217             throw new NotActiveException();
   2218         }
   2219         if (object == null) {
   2220             throw new InvalidObjectException("Callback object cannot be null");
   2221         }
   2222         // From now on it is just insertion in a SortedCollection. Since
   2223         // the Java class libraries don't provide that, we have to
   2224         // implement it from scratch here.
   2225         InputValidationDesc desc = new InputValidationDesc();
   2226         desc.validator = object;
   2227         desc.priority = priority;
   2228         // No need for this, validateObject does not take a parameter
   2229         // desc.toValidate = instanceBeingRead;
   2230         if (validations == null) {
   2231             validations = new InputValidationDesc[1];
   2232             validations[0] = desc;
   2233         } else {
   2234             int i = 0;
   2235             for (; i < validations.length; i++) {
   2236                 InputValidationDesc validation = validations[i];
   2237                 // Sorted, higher priority first.
   2238                 if (priority >= validation.priority) {
   2239                     break; // Found the index where to insert
   2240                 }
   2241             }
   2242             InputValidationDesc[] oldValidations = validations;
   2243             int currentSize = oldValidations.length;
   2244             validations = new InputValidationDesc[currentSize + 1];
   2245             System.arraycopy(oldValidations, 0, validations, 0, i);
   2246             System.arraycopy(oldValidations, i, validations, i + 1, currentSize
   2247                     - i);
   2248             validations[i] = desc;
   2249         }
   2250     }
   2251 
   2252     /**
   2253      * Reset the collection of objects already loaded by the receiver.
   2254      */
   2255     private void resetSeenObjects() {
   2256         objectsRead = new ArrayList<Object>();
   2257         nextHandle = baseWireHandle;
   2258         primitiveData = emptyStream;
   2259     }
   2260 
   2261     /**
   2262      * Reset the receiver. The collection of objects already read by the
   2263      * receiver is reset, and internal structures are also reset so that the
   2264      * receiver knows it is in a fresh clean state.
   2265      */
   2266     private void resetState() {
   2267         resetSeenObjects();
   2268         hasPushbackTC = false;
   2269         pushbackTC = 0;
   2270         // nestedLevels = 0;
   2271     }
   2272 
   2273     /**
   2274      * Loads the Java class corresponding to the class descriptor {@code
   2275      * osClass} that has just been read from the source stream.
   2276      *
   2277      * @param osClass
   2278      *            an ObjectStreamClass read from the source stream.
   2279      * @return a Class corresponding to the descriptor {@code osClass}.
   2280      * @throws ClassNotFoundException
   2281      *             if the class for an object cannot be found.
   2282      * @throws IOException
   2283      *             if an I/O error occurs while creating the class.
   2284      * @see ObjectOutputStream#annotateClass(Class)
   2285      */
   2286     protected Class<?> resolveClass(ObjectStreamClass osClass)
   2287             throws IOException, ClassNotFoundException {
   2288         // fastpath: obtain cached value
   2289         Class<?> cls = osClass.forClass();
   2290         if (cls == null) {
   2291             // slowpath: resolve the class
   2292             String className = osClass.getName();
   2293 
   2294             // if it is primitive class, for example, long.class
   2295             cls = PRIMITIVE_CLASSES.get(className);
   2296 
   2297             if (cls == null) {
   2298                 // not primitive class
   2299                 // Use the first non-null ClassLoader on the stack. If null, use
   2300                 // the system class loader
   2301                 cls = Class.forName(className, true, callerClassLoader);
   2302             }
   2303         }
   2304         return cls;
   2305     }
   2306 
   2307     /**
   2308      * Allows trusted subclasses to substitute the specified original {@code
   2309      * object} with a new object. Object substitution has to be activated first
   2310      * with calling {@code enableResolveObject(true)}. This implementation just
   2311      * returns {@code object}.
   2312      *
   2313      * @param object
   2314      *            the original object for which a replacement may be defined.
   2315      * @return the replacement object for {@code object}.
   2316      * @throws IOException
   2317      *             if any I/O error occurs while creating the replacement
   2318      *             object.
   2319      * @see #enableResolveObject
   2320      * @see ObjectOutputStream#enableReplaceObject
   2321      * @see ObjectOutputStream#replaceObject
   2322      */
   2323     protected Object resolveObject(Object object) throws IOException {
   2324         // By default no object replacement. Subclasses can override
   2325         return object;
   2326     }
   2327 
   2328     /**
   2329      * Skips {@code length} bytes on the source stream. This method should not
   2330      * be used to skip bytes at any arbitrary position, just when reading
   2331      * primitive data types (int, char etc).
   2332      *
   2333      * @param length
   2334      *            the number of bytes to skip.
   2335      * @return the number of bytes actually skipped.
   2336      * @throws IOException
   2337      *             if an error occurs while skipping bytes on the source stream.
   2338      * @throws NullPointerException
   2339      *             if the source stream is {@code null}.
   2340      */
   2341     public int skipBytes(int length) throws IOException {
   2342         // To be used with available. Ok to call if reading primitive buffer
   2343         if (input == null) {
   2344             throw new NullPointerException();
   2345         }
   2346 
   2347         int offset = 0;
   2348         while (offset < length) {
   2349             checkReadPrimitiveTypes();
   2350             long skipped = primitiveData.skip(length - offset);
   2351             if (skipped == 0) {
   2352                 return offset;
   2353             }
   2354             offset += (int) skipped;
   2355         }
   2356         return length;
   2357     }
   2358 
   2359     /**
   2360      * Verify if the SUID & the base name for descriptor
   2361      * <code>loadedStreamClass</code>matches
   2362      * the SUID & the base name of the corresponding loaded class and
   2363      * init private fields.
   2364      *
   2365      * @param loadedStreamClass
   2366      *            An ObjectStreamClass that was loaded from the stream.
   2367      *
   2368      * @throws InvalidClassException
   2369      *             If the SUID of the stream class does not match the VM class
   2370      */
   2371     private void verifyAndInit(ObjectStreamClass loadedStreamClass)
   2372             throws InvalidClassException {
   2373 
   2374         Class<?> localClass = loadedStreamClass.forClass();
   2375         ObjectStreamClass localStreamClass = ObjectStreamClass
   2376                 .lookupStreamClass(localClass);
   2377 
   2378         if (loadedStreamClass.getSerialVersionUID() != localStreamClass
   2379                 .getSerialVersionUID()) {
   2380             throw new InvalidClassException(loadedStreamClass.getName(),
   2381                     "Incompatible class (SUID): " + loadedStreamClass +
   2382                             " but expected " + localStreamClass);
   2383         }
   2384 
   2385         String loadedClassBaseName = getBaseName(loadedStreamClass.getName());
   2386         String localClassBaseName = getBaseName(localStreamClass.getName());
   2387 
   2388         if (!loadedClassBaseName.equals(localClassBaseName)) {
   2389             throw new InvalidClassException(loadedStreamClass.getName(),
   2390                     String.format("Incompatible class (base name): %s but expected %s",
   2391                             loadedClassBaseName, localClassBaseName));
   2392         }
   2393 
   2394         loadedStreamClass.initPrivateFields(localStreamClass);
   2395     }
   2396 
   2397     private static String getBaseName(String fullName) {
   2398         int k = fullName.lastIndexOf('.');
   2399 
   2400         if (k == -1 || k == (fullName.length() - 1)) {
   2401             return fullName;
   2402         }
   2403         return fullName.substring(k + 1);
   2404     }
   2405 
   2406     // Avoid recursive defining.
   2407     private static void checkedSetSuperClassDesc(ObjectStreamClass desc,
   2408             ObjectStreamClass superDesc) throws StreamCorruptedException {
   2409         if (desc.equals(superDesc)) {
   2410             throw new StreamCorruptedException();
   2411         }
   2412         desc.setSuperclass(superDesc);
   2413     }
   2414 }
   2415