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