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