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