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