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