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