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