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