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