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