1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. Oracle designates this 9 * particular file as subject to the "Classpath" exception as provided 10 * by Oracle in the LICENSE file that accompanied this code. 11 * 12 * This code is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 * version 2 for more details (a copy is included in the LICENSE file that 16 * accompanied this code). 17 * 18 * You should have received a copy of the GNU General Public License version 19 * 2 along with this work; if not, write to the Free Software Foundation, 20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 * 22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 * or visit www.oracle.com if you need additional information or have any 24 * questions. 25 */ 26 27 package java.io; 28 29 import java.io.ObjectStreamClass.WeakClassKey; 30 import java.lang.ref.ReferenceQueue; 31 import java.security.AccessController; 32 import java.security.PrivilegedAction; 33 import java.util.ArrayList; 34 import java.util.Arrays; 35 import java.util.List; 36 import java.util.concurrent.ConcurrentHashMap; 37 import java.util.concurrent.ConcurrentMap; 38 import static java.io.ObjectStreamClass.processQueue; 39 import java.io.SerialCallbackContext; 40 41 import sun.reflect.misc.ReflectUtil; 42 43 /** 44 * An ObjectOutputStream writes primitive data types and graphs of Java objects 45 * to an OutputStream. The objects can be read (reconstituted) using an 46 * ObjectInputStream. Persistent storage of objects can be accomplished by 47 * using a file for the stream. If the stream is a network socket stream, the 48 * objects can be reconstituted on another host or in another process. 49 * 50 * <p>Only objects that support the java.io.Serializable interface can be 51 * written to streams. The class of each serializable object is encoded 52 * including the class name and signature of the class, the values of the 53 * object's fields and arrays, and the closure of any other objects referenced 54 * from the initial objects. 55 * 56 * <p>The method writeObject is used to write an object to the stream. Any 57 * object, including Strings and arrays, is written with writeObject. Multiple 58 * objects or primitives can be written to the stream. The objects must be 59 * read back from the corresponding ObjectInputstream with the same types and 60 * in the same order as they were written. 61 * 62 * <p>Primitive data types can also be written to the stream using the 63 * appropriate methods from DataOutput. Strings can also be written using the 64 * writeUTF method. 65 * 66 * <p>The default serialization mechanism for an object writes the class of the 67 * object, the class signature, and the values of all non-transient and 68 * non-static fields. References to other objects (except in transient or 69 * static fields) cause those objects to be written also. Multiple references 70 * to a single object are encoded using a reference sharing mechanism so that 71 * graphs of objects can be restored to the same shape as when the original was 72 * written. 73 * 74 * <p>For example to write an object that can be read by the example in 75 * ObjectInputStream: 76 * <br> 77 * <pre> 78 * FileOutputStream fos = new FileOutputStream("t.tmp"); 79 * ObjectOutputStream oos = new ObjectOutputStream(fos); 80 * 81 * oos.writeInt(12345); 82 * oos.writeObject("Today"); 83 * oos.writeObject(new Date()); 84 * 85 * oos.close(); 86 * </pre> 87 * 88 * <p>Classes that require special handling during the serialization and 89 * deserialization process must implement special methods with these exact 90 * signatures: 91 * <br> 92 * <pre> 93 * private void readObject(java.io.ObjectInputStream stream) 94 * throws IOException, ClassNotFoundException; 95 * private void writeObject(java.io.ObjectOutputStream stream) 96 * throws IOException 97 * private void readObjectNoData() 98 * throws ObjectStreamException; 99 * </pre> 100 * 101 * <p>The writeObject method is responsible for writing the state of the object 102 * for its particular class so that the corresponding readObject method can 103 * restore it. The method does not need to concern itself with the state 104 * belonging to the object's superclasses or subclasses. State is saved by 105 * writing the individual fields to the ObjectOutputStream using the 106 * writeObject method or by using the methods for primitive data types 107 * supported by DataOutput. 108 * 109 * <p>Serialization does not write out the fields of any object that does not 110 * implement the java.io.Serializable interface. Subclasses of Objects that 111 * are not serializable can be serializable. In this case the non-serializable 112 * class must have a no-arg constructor to allow its fields to be initialized. 113 * In this case it is the responsibility of the subclass to save and restore 114 * the state of the non-serializable class. It is frequently the case that the 115 * fields of that class are accessible (public, package, or protected) or that 116 * there are get and set methods that can be used to restore the state. 117 * 118 * <p>Serialization of an object can be prevented by implementing writeObject 119 * and readObject methods that throw the NotSerializableException. The 120 * exception will be caught by the ObjectOutputStream and abort the 121 * serialization process. 122 * 123 * <p>Implementing the Externalizable interface allows the object to assume 124 * complete control over the contents and format of the object's serialized 125 * form. The methods of the Externalizable interface, writeExternal and 126 * readExternal, are called to save and restore the objects state. When 127 * implemented by a class they can write and read their own state using all of 128 * the methods of ObjectOutput and ObjectInput. It is the responsibility of 129 * the objects to handle any versioning that occurs. 130 * 131 * <p>Enum constants are serialized differently than ordinary serializable or 132 * externalizable objects. The serialized form of an enum constant consists 133 * solely of its name; field values of the constant are not transmitted. To 134 * serialize an enum constant, ObjectOutputStream writes the string returned by 135 * the constant's name method. Like other serializable or externalizable 136 * objects, enum constants can function as the targets of back references 137 * appearing subsequently in the serialization stream. The process by which 138 * enum constants are serialized cannot be customized; any class-specific 139 * writeObject and writeReplace methods defined by enum types are ignored 140 * during serialization. Similarly, any serialPersistentFields or 141 * serialVersionUID field declarations are also ignored--all enum types have a 142 * fixed serialVersionUID of 0L. 143 * 144 * <p>Primitive data, excluding serializable fields and externalizable data, is 145 * written to the ObjectOutputStream in block-data records. A block data record 146 * is composed of a header and data. The block data header consists of a marker 147 * and the number of bytes to follow the header. Consecutive primitive data 148 * writes are merged into one block-data record. The blocking factor used for 149 * a block-data record will be 1024 bytes. Each block-data record will be 150 * filled up to 1024 bytes, or be written whenever there is a termination of 151 * block-data mode. Calls to the ObjectOutputStream methods writeObject, 152 * defaultWriteObject and writeFields initially terminate any existing 153 * block-data record. 154 * 155 * @author Mike Warres 156 * @author Roger Riggs 157 * @see java.io.DataOutput 158 * @see java.io.ObjectInputStream 159 * @see java.io.Serializable 160 * @see java.io.Externalizable 161 * @see <a href="{@docRoot}openjdk-redirect.html?v=8&path=/platform/serialization/spec/output.html">Object Serialization Specification, Section 2, Object Output Classes</a> 162 * @since JDK1.1 163 */ 164 public class ObjectOutputStream 165 extends OutputStream implements ObjectOutput, ObjectStreamConstants 166 { 167 168 private static class Caches { 169 /** cache of subclass security audit results */ 170 static final ConcurrentMap<WeakClassKey,Boolean> subclassAudits = 171 new ConcurrentHashMap<>(); 172 173 /** queue for WeakReferences to audited subclasses */ 174 static final ReferenceQueue<Class<?>> subclassAuditsQueue = 175 new ReferenceQueue<>(); 176 } 177 178 /** filter stream for handling block data conversion */ 179 private final BlockDataOutputStream bout; 180 /** obj -> wire handle map */ 181 private final HandleTable handles; 182 /** obj -> replacement obj map */ 183 private final ReplaceTable subs; 184 /** stream protocol version */ 185 private int protocol = PROTOCOL_VERSION_2; 186 /** recursion depth */ 187 private int depth; 188 189 /** buffer for writing primitive field values */ 190 private byte[] primVals; 191 192 /** if true, invoke writeObjectOverride() instead of writeObject() */ 193 private final boolean enableOverride; 194 /** if true, invoke replaceObject() */ 195 private boolean enableReplace; 196 197 // values below valid only during upcalls to writeObject()/writeExternal() 198 /** 199 * Context during upcalls to class-defined writeObject methods; holds 200 * object currently being serialized and descriptor for current class. 201 * Null when not during writeObject upcall. 202 */ 203 private SerialCallbackContext curContext; 204 /** current PutField object */ 205 private PutFieldImpl curPut; 206 207 /** custom storage for debug trace info */ 208 private final DebugTraceInfoStack debugInfoStack; 209 210 /** 211 * value of "sun.io.serialization.extendedDebugInfo" property, 212 * as true or false for extended information about exception's place 213 */ 214 private static final boolean extendedDebugInfo = false; 215 216 /** 217 * Creates an ObjectOutputStream that writes to the specified OutputStream. 218 * This constructor writes the serialization stream header to the 219 * underlying stream; callers may wish to flush the stream immediately to 220 * ensure that constructors for receiving ObjectInputStreams will not block 221 * when reading the header. 222 * 223 * <p>If a security manager is installed, this constructor will check for 224 * the "enableSubclassImplementation" SerializablePermission when invoked 225 * directly or indirectly by the constructor of a subclass which overrides 226 * the ObjectOutputStream.putFields or ObjectOutputStream.writeUnshared 227 * methods. 228 * 229 * @param out output stream to write to 230 * @throws IOException if an I/O error occurs while writing stream header 231 * @throws SecurityException if untrusted subclass illegally overrides 232 * security-sensitive methods 233 * @throws NullPointerException if <code>out</code> is <code>null</code> 234 * @since 1.4 235 * @see ObjectOutputStream#ObjectOutputStream() 236 * @see ObjectOutputStream#putFields() 237 * @see ObjectInputStream#ObjectInputStream(InputStream) 238 */ ObjectOutputStream(OutputStream out)239 public ObjectOutputStream(OutputStream out) throws IOException { 240 verifySubclass(); 241 bout = new BlockDataOutputStream(out); 242 handles = new HandleTable(10, (float) 3.00); 243 subs = new ReplaceTable(10, (float) 3.00); 244 enableOverride = false; 245 writeStreamHeader(); 246 bout.setBlockDataMode(true); 247 if (extendedDebugInfo) { 248 debugInfoStack = new DebugTraceInfoStack(); 249 } else { 250 debugInfoStack = null; 251 } 252 } 253 254 /** 255 * Provide a way for subclasses that are completely reimplementing 256 * ObjectOutputStream to not have to allocate private data just used by 257 * this implementation of ObjectOutputStream. 258 * 259 * <p>If there is a security manager installed, this method first calls the 260 * security manager's <code>checkPermission</code> method with a 261 * <code>SerializablePermission("enableSubclassImplementation")</code> 262 * permission to ensure it's ok to enable subclassing. 263 * 264 * @throws SecurityException if a security manager exists and its 265 * <code>checkPermission</code> method denies enabling 266 * subclassing. 267 * @throws IOException if an I/O error occurs while creating this stream 268 * @see SecurityManager#checkPermission 269 * @see java.io.SerializablePermission 270 */ ObjectOutputStream()271 protected ObjectOutputStream() throws IOException, SecurityException { 272 SecurityManager sm = System.getSecurityManager(); 273 if (sm != null) { 274 sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); 275 } 276 bout = null; 277 handles = null; 278 subs = null; 279 enableOverride = true; 280 debugInfoStack = null; 281 } 282 283 /** 284 * Specify stream protocol version to use when writing the stream. 285 * 286 * <p>This routine provides a hook to enable the current version of 287 * Serialization to write in a format that is backwards compatible to a 288 * previous version of the stream format. 289 * 290 * <p>Every effort will be made to avoid introducing additional 291 * backwards incompatibilities; however, sometimes there is no 292 * other alternative. 293 * 294 * @param version use ProtocolVersion from java.io.ObjectStreamConstants. 295 * @throws IllegalStateException if called after any objects 296 * have been serialized. 297 * @throws IllegalArgumentException if invalid version is passed in. 298 * @throws IOException if I/O errors occur 299 * @see java.io.ObjectStreamConstants#PROTOCOL_VERSION_1 300 * @see java.io.ObjectStreamConstants#PROTOCOL_VERSION_2 301 * @since 1.2 302 */ useProtocolVersion(int version)303 public void useProtocolVersion(int version) throws IOException { 304 if (handles.size() != 0) { 305 // REMIND: implement better check for pristine stream? 306 throw new IllegalStateException("stream non-empty"); 307 } 308 switch (version) { 309 case PROTOCOL_VERSION_1: 310 case PROTOCOL_VERSION_2: 311 protocol = version; 312 break; 313 314 default: 315 throw new IllegalArgumentException( 316 "unknown version: " + version); 317 } 318 } 319 320 /** 321 * Write the specified object to the ObjectOutputStream. The class of the 322 * object, the signature of the class, and the values of the non-transient 323 * and non-static fields of the class and all of its supertypes are 324 * written. Default serialization for a class can be overridden using the 325 * writeObject and the readObject methods. Objects referenced by this 326 * object are written transitively so that a complete equivalent graph of 327 * objects can be reconstructed by an ObjectInputStream. 328 * 329 * <p>Exceptions are thrown for problems with the OutputStream and for 330 * classes that should not be serialized. All exceptions are fatal to the 331 * OutputStream, which is left in an indeterminate state, and it is up to 332 * the caller to ignore or recover the stream state. 333 * 334 * @throws InvalidClassException Something is wrong with a class used by 335 * serialization. 336 * @throws NotSerializableException Some object to be serialized does not 337 * implement the java.io.Serializable interface. 338 * @throws IOException Any exception thrown by the underlying 339 * OutputStream. 340 */ writeObject(Object obj)341 public final void writeObject(Object obj) throws IOException { 342 if (enableOverride) { 343 writeObjectOverride(obj); 344 return; 345 } 346 try { 347 writeObject0(obj, false); 348 } catch (IOException ex) { 349 if (depth == 0) { 350 // BEGIN Android-changed 351 // writeFatalException(ex); 352 try { 353 writeFatalException(ex); 354 355 } catch (IOException ex2) { 356 // If writing the exception to the output stream causes another exception there 357 // is no need to propagate the second exception or generate a third exception, 358 // both of which might obscure details of the root cause. 359 } 360 // END Android-changed 361 } 362 throw ex; 363 } 364 } 365 366 /** 367 * Method used by subclasses to override the default writeObject method. 368 * This method is called by trusted subclasses of ObjectInputStream that 369 * constructed ObjectInputStream using the protected no-arg constructor. 370 * The subclass is expected to provide an override method with the modifier 371 * "final". 372 * 373 * @param obj object to be written to the underlying stream 374 * @throws IOException if there are I/O errors while writing to the 375 * underlying stream 376 * @see #ObjectOutputStream() 377 * @see #writeObject(Object) 378 * @since 1.2 379 */ writeObjectOverride(Object obj)380 protected void writeObjectOverride(Object obj) throws IOException { 381 // BEGIN Android-changed 382 if (!enableOverride) { 383 // Subclasses must override. 384 throw new IOException(); 385 } 386 // END Android-changed 387 } 388 389 /** 390 * Writes an "unshared" object to the ObjectOutputStream. This method is 391 * identical to writeObject, except that it always writes the given object 392 * as a new, unique object in the stream (as opposed to a back-reference 393 * pointing to a previously serialized instance). Specifically: 394 * <ul> 395 * <li>An object written via writeUnshared is always serialized in the 396 * same manner as a newly appearing object (an object that has not 397 * been written to the stream yet), regardless of whether or not the 398 * object has been written previously. 399 * 400 * <li>If writeObject is used to write an object that has been previously 401 * written with writeUnshared, the previous writeUnshared operation 402 * is treated as if it were a write of a separate object. In other 403 * words, ObjectOutputStream will never generate back-references to 404 * object data written by calls to writeUnshared. 405 * </ul> 406 * While writing an object via writeUnshared does not in itself guarantee a 407 * unique reference to the object when it is deserialized, it allows a 408 * single object to be defined multiple times in a stream, so that multiple 409 * calls to readUnshared by the receiver will not conflict. Note that the 410 * rules described above only apply to the base-level object written with 411 * writeUnshared, and not to any transitively referenced sub-objects in the 412 * object graph to be serialized. 413 * 414 * <p>ObjectOutputStream subclasses which override this method can only be 415 * constructed in security contexts possessing the 416 * "enableSubclassImplementation" SerializablePermission; any attempt to 417 * instantiate such a subclass without this permission will cause a 418 * SecurityException to be thrown. 419 * 420 * @param obj object to write to stream 421 * @throws NotSerializableException if an object in the graph to be 422 * serialized does not implement the Serializable interface 423 * @throws InvalidClassException if a problem exists with the class of an 424 * object to be serialized 425 * @throws IOException if an I/O error occurs during serialization 426 * @since 1.4 427 */ writeUnshared(Object obj)428 public void writeUnshared(Object obj) throws IOException { 429 try { 430 writeObject0(obj, true); 431 } catch (IOException ex) { 432 if (depth == 0) { 433 writeFatalException(ex); 434 } 435 throw ex; 436 } 437 } 438 439 /** 440 * Write the non-static and non-transient fields of the current class to 441 * this stream. This may only be called from the writeObject method of the 442 * class being serialized. It will throw the NotActiveException if it is 443 * called otherwise. 444 * 445 * @throws IOException if I/O errors occur while writing to the underlying 446 * <code>OutputStream</code> 447 */ defaultWriteObject()448 public void defaultWriteObject() throws IOException { 449 SerialCallbackContext ctx = curContext; 450 if (ctx == null) { 451 throw new NotActiveException("not in call to writeObject"); 452 } 453 Object curObj = ctx.getObj(); 454 ObjectStreamClass curDesc = ctx.getDesc(); 455 bout.setBlockDataMode(false); 456 defaultWriteFields(curObj, curDesc); 457 bout.setBlockDataMode(true); 458 } 459 460 /** 461 * Retrieve the object used to buffer persistent fields to be written to 462 * the stream. The fields will be written to the stream when writeFields 463 * method is called. 464 * 465 * @return an instance of the class Putfield that holds the serializable 466 * fields 467 * @throws IOException if I/O errors occur 468 * @since 1.2 469 */ putFields()470 public ObjectOutputStream.PutField putFields() throws IOException { 471 if (curPut == null) { 472 SerialCallbackContext ctx = curContext; 473 if (ctx == null) { 474 throw new NotActiveException("not in call to writeObject"); 475 } 476 Object curObj = ctx.getObj(); 477 ObjectStreamClass curDesc = ctx.getDesc(); 478 curPut = new PutFieldImpl(curDesc); 479 } 480 return curPut; 481 } 482 483 /** 484 * Write the buffered fields to the stream. 485 * 486 * @throws IOException if I/O errors occur while writing to the underlying 487 * stream 488 * @throws NotActiveException Called when a classes writeObject method was 489 * not called to write the state of the object. 490 * @since 1.2 491 */ writeFields()492 public void writeFields() throws IOException { 493 if (curPut == null) { 494 throw new NotActiveException("no current PutField object"); 495 } 496 bout.setBlockDataMode(false); 497 curPut.writeFields(); 498 bout.setBlockDataMode(true); 499 } 500 501 /** 502 * Reset will disregard the state of any objects already written to the 503 * stream. The state is reset to be the same as a new ObjectOutputStream. 504 * The current point in the stream is marked as reset so the corresponding 505 * ObjectInputStream will be reset at the same point. Objects previously 506 * written to the stream will not be referred to as already being in the 507 * stream. They will be written to the stream again. 508 * 509 * @throws IOException if reset() is invoked while serializing an object. 510 */ reset()511 public void reset() throws IOException { 512 if (depth != 0) { 513 throw new IOException("stream active"); 514 } 515 bout.setBlockDataMode(false); 516 bout.writeByte(TC_RESET); 517 clear(); 518 bout.setBlockDataMode(true); 519 } 520 521 /** 522 * Subclasses may implement this method to allow class data to be stored in 523 * the stream. By default this method does nothing. The corresponding 524 * method in ObjectInputStream is resolveClass. This method is called 525 * exactly once for each unique class in the stream. The class name and 526 * signature will have already been written to the stream. This method may 527 * make free use of the ObjectOutputStream to save any representation of 528 * the class it deems suitable (for example, the bytes of the class file). 529 * The resolveClass method in the corresponding subclass of 530 * ObjectInputStream must read and use any data or objects written by 531 * annotateClass. 532 * 533 * @param cl the class to annotate custom data for 534 * @throws IOException Any exception thrown by the underlying 535 * OutputStream. 536 */ annotateClass(Class<?> cl)537 protected void annotateClass(Class<?> cl) throws IOException { 538 } 539 540 /** 541 * Subclasses may implement this method to store custom data in the stream 542 * along with descriptors for dynamic proxy classes. 543 * 544 * <p>This method is called exactly once for each unique proxy class 545 * descriptor in the stream. The default implementation of this method in 546 * <code>ObjectOutputStream</code> does nothing. 547 * 548 * <p>The corresponding method in <code>ObjectInputStream</code> is 549 * <code>resolveProxyClass</code>. For a given subclass of 550 * <code>ObjectOutputStream</code> that overrides this method, the 551 * <code>resolveProxyClass</code> method in the corresponding subclass of 552 * <code>ObjectInputStream</code> must read any data or objects written by 553 * <code>annotateProxyClass</code>. 554 * 555 * @param cl the proxy class to annotate custom data for 556 * @throws IOException any exception thrown by the underlying 557 * <code>OutputStream</code> 558 * @see ObjectInputStream#resolveProxyClass(String[]) 559 * @since 1.3 560 */ annotateProxyClass(Class<?> cl)561 protected void annotateProxyClass(Class<?> cl) throws IOException { 562 } 563 564 /** 565 * This method will allow trusted subclasses of ObjectOutputStream to 566 * substitute one object for another during serialization. Replacing 567 * objects is disabled until enableReplaceObject is called. The 568 * enableReplaceObject method checks that the stream requesting to do 569 * replacement can be trusted. The first occurrence of each object written 570 * into the serialization stream is passed to replaceObject. Subsequent 571 * references to the object are replaced by the object returned by the 572 * original call to replaceObject. To ensure that the private state of 573 * objects is not unintentionally exposed, only trusted streams may use 574 * replaceObject. 575 * 576 * <p>The ObjectOutputStream.writeObject method takes a parameter of type 577 * Object (as opposed to type Serializable) to allow for cases where 578 * non-serializable objects are replaced by serializable ones. 579 * 580 * <p>When a subclass is replacing objects it must insure that either a 581 * complementary substitution must be made during deserialization or that 582 * the substituted object is compatible with every field where the 583 * reference will be stored. Objects whose type is not a subclass of the 584 * type of the field or array element abort the serialization by raising an 585 * exception and the object is not be stored. 586 * 587 * <p>This method is called only once when each object is first 588 * encountered. All subsequent references to the object will be redirected 589 * to the new object. This method should return the object to be 590 * substituted or the original object. 591 * 592 * <p>Null can be returned as the object to be substituted, but may cause 593 * NullReferenceException in classes that contain references to the 594 * original object since they may be expecting an object instead of 595 * null. 596 * 597 * @param obj the object to be replaced 598 * @return the alternate object that replaced the specified one 599 * @throws IOException Any exception thrown by the underlying 600 * OutputStream. 601 */ replaceObject(Object obj)602 protected Object replaceObject(Object obj) throws IOException { 603 return obj; 604 } 605 606 /** 607 * Enable the stream to do replacement of objects in the stream. When 608 * enabled, the replaceObject method is called for every object being 609 * serialized. 610 * 611 * <p>If <code>enable</code> is true, and there is a security manager 612 * installed, this method first calls the security manager's 613 * <code>checkPermission</code> method with a 614 * <code>SerializablePermission("enableSubstitution")</code> permission to 615 * ensure it's ok to enable the stream to do replacement of objects in the 616 * stream. 617 * 618 * @param enable boolean parameter to enable replacement of objects 619 * @return the previous setting before this method was invoked 620 * @throws SecurityException if a security manager exists and its 621 * <code>checkPermission</code> method denies enabling the stream 622 * to do replacement of objects in the stream. 623 * @see SecurityManager#checkPermission 624 * @see java.io.SerializablePermission 625 */ enableReplaceObject(boolean enable)626 protected boolean enableReplaceObject(boolean enable) 627 throws SecurityException 628 { 629 if (enable == enableReplace) { 630 return enable; 631 } 632 if (enable) { 633 SecurityManager sm = System.getSecurityManager(); 634 if (sm != null) { 635 sm.checkPermission(SUBSTITUTION_PERMISSION); 636 } 637 } 638 enableReplace = enable; 639 return !enableReplace; 640 } 641 642 /** 643 * The writeStreamHeader method is provided so subclasses can append or 644 * prepend their own header to the stream. It writes the magic number and 645 * version to the stream. 646 * 647 * @throws IOException if I/O errors occur while writing to the underlying 648 * stream 649 */ writeStreamHeader()650 protected void writeStreamHeader() throws IOException { 651 bout.writeShort(STREAM_MAGIC); 652 bout.writeShort(STREAM_VERSION); 653 } 654 655 /** 656 * Write the specified class descriptor to the ObjectOutputStream. Class 657 * descriptors are used to identify the classes of objects written to the 658 * stream. Subclasses of ObjectOutputStream may override this method to 659 * customize the way in which class descriptors are written to the 660 * serialization stream. The corresponding method in ObjectInputStream, 661 * <code>readClassDescriptor</code>, should then be overridden to 662 * reconstitute the class descriptor from its custom stream representation. 663 * By default, this method writes class descriptors according to the format 664 * defined in the Object Serialization specification. 665 * 666 * <p>Note that this method will only be called if the ObjectOutputStream 667 * is not using the old serialization stream format (set by calling 668 * ObjectOutputStream's <code>useProtocolVersion</code> method). If this 669 * serialization stream is using the old format 670 * (<code>PROTOCOL_VERSION_1</code>), the class descriptor will be written 671 * internally in a manner that cannot be overridden or customized. 672 * 673 * @param desc class descriptor to write to the stream 674 * @throws IOException If an I/O error has occurred. 675 * @see java.io.ObjectInputStream#readClassDescriptor() 676 * @see #useProtocolVersion(int) 677 * @see java.io.ObjectStreamConstants#PROTOCOL_VERSION_1 678 * @since 1.3 679 */ writeClassDescriptor(ObjectStreamClass desc)680 protected void writeClassDescriptor(ObjectStreamClass desc) 681 throws IOException 682 { 683 desc.writeNonProxy(this); 684 } 685 686 /** 687 * Writes a byte. This method will block until the byte is actually 688 * written. 689 * 690 * @param val the byte to be written to the stream 691 * @throws IOException If an I/O error has occurred. 692 */ write(int val)693 public void write(int val) throws IOException { 694 bout.write(val); 695 } 696 697 /** 698 * Writes an array of bytes. This method will block until the bytes are 699 * actually written. 700 * 701 * @param buf the data to be written 702 * @throws IOException If an I/O error has occurred. 703 */ write(byte[] buf)704 public void write(byte[] buf) throws IOException { 705 bout.write(buf, 0, buf.length, false); 706 } 707 708 /** 709 * Writes a sub array of bytes. 710 * 711 * @param buf the data to be written 712 * @param off the start offset in the data 713 * @param len the number of bytes that are written 714 * @throws IOException If an I/O error has occurred. 715 */ write(byte[] buf, int off, int len)716 public void write(byte[] buf, int off, int len) throws IOException { 717 if (buf == null) { 718 throw new NullPointerException(); 719 } 720 int endoff = off + len; 721 if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) { 722 throw new IndexOutOfBoundsException(); 723 } 724 bout.write(buf, off, len, false); 725 } 726 727 /** 728 * Flushes the stream. This will write any buffered output bytes and flush 729 * through to the underlying stream. 730 * 731 * @throws IOException If an I/O error has occurred. 732 */ flush()733 public void flush() throws IOException { 734 bout.flush(); 735 } 736 737 /** 738 * Drain any buffered data in ObjectOutputStream. Similar to flush but 739 * does not propagate the flush to the underlying stream. 740 * 741 * @throws IOException if I/O errors occur while writing to the underlying 742 * stream 743 */ drain()744 protected void drain() throws IOException { 745 bout.drain(); 746 } 747 748 /** 749 * Closes the stream. This method must be called to release any resources 750 * associated with the stream. 751 * 752 * @throws IOException If an I/O error has occurred. 753 */ close()754 public void close() throws IOException { 755 flush(); 756 // http://b/28159133 757 // clear(); 758 bout.close(); 759 } 760 761 /** 762 * Writes a boolean. 763 * 764 * @param val the boolean to be written 765 * @throws IOException if I/O errors occur while writing to the underlying 766 * stream 767 */ writeBoolean(boolean val)768 public void writeBoolean(boolean val) throws IOException { 769 bout.writeBoolean(val); 770 } 771 772 /** 773 * Writes an 8 bit byte. 774 * 775 * @param val the byte value to be written 776 * @throws IOException if I/O errors occur while writing to the underlying 777 * stream 778 */ writeByte(int val)779 public void writeByte(int val) throws IOException { 780 bout.writeByte(val); 781 } 782 783 /** 784 * Writes a 16 bit short. 785 * 786 * @param val the short value to be written 787 * @throws IOException if I/O errors occur while writing to the underlying 788 * stream 789 */ writeShort(int val)790 public void writeShort(int val) throws IOException { 791 bout.writeShort(val); 792 } 793 794 /** 795 * Writes a 16 bit char. 796 * 797 * @param val the char value to be written 798 * @throws IOException if I/O errors occur while writing to the underlying 799 * stream 800 */ writeChar(int val)801 public void writeChar(int val) throws IOException { 802 bout.writeChar(val); 803 } 804 805 /** 806 * Writes a 32 bit int. 807 * 808 * @param val the integer value to be written 809 * @throws IOException if I/O errors occur while writing to the underlying 810 * stream 811 */ writeInt(int val)812 public void writeInt(int val) throws IOException { 813 bout.writeInt(val); 814 } 815 816 /** 817 * Writes a 64 bit long. 818 * 819 * @param val the long value to be written 820 * @throws IOException if I/O errors occur while writing to the underlying 821 * stream 822 */ writeLong(long val)823 public void writeLong(long val) throws IOException { 824 bout.writeLong(val); 825 } 826 827 /** 828 * Writes a 32 bit float. 829 * 830 * @param val the float value to be written 831 * @throws IOException if I/O errors occur while writing to the underlying 832 * stream 833 */ writeFloat(float val)834 public void writeFloat(float val) throws IOException { 835 bout.writeFloat(val); 836 } 837 838 /** 839 * Writes a 64 bit double. 840 * 841 * @param val the double value to be written 842 * @throws IOException if I/O errors occur while writing to the underlying 843 * stream 844 */ writeDouble(double val)845 public void writeDouble(double val) throws IOException { 846 bout.writeDouble(val); 847 } 848 849 /** 850 * Writes a String as a sequence of bytes. 851 * 852 * @param str the String of bytes to be written 853 * @throws IOException if I/O errors occur while writing to the underlying 854 * stream 855 */ writeBytes(String str)856 public void writeBytes(String str) throws IOException { 857 bout.writeBytes(str); 858 } 859 860 /** 861 * Writes a String as a sequence of chars. 862 * 863 * @param str the String of chars to be written 864 * @throws IOException if I/O errors occur while writing to the underlying 865 * stream 866 */ writeChars(String str)867 public void writeChars(String str) throws IOException { 868 bout.writeChars(str); 869 } 870 871 /** 872 * Primitive data write of this String in 873 * <a href="DataInput.html#modified-utf-8">modified UTF-8</a> 874 * format. Note that there is a 875 * significant difference between writing a String into the stream as 876 * primitive data or as an Object. A String instance written by writeObject 877 * is written into the stream as a String initially. Future writeObject() 878 * calls write references to the string into the stream. 879 * 880 * @param str the String to be written 881 * @throws IOException if I/O errors occur while writing to the underlying 882 * stream 883 */ writeUTF(String str)884 public void writeUTF(String str) throws IOException { 885 bout.writeUTF(str); 886 } 887 888 /** 889 * Provide programmatic access to the persistent fields to be written 890 * to ObjectOutput. 891 * 892 * @since 1.2 893 */ 894 public static abstract class PutField { 895 896 /** 897 * Put the value of the named boolean field into the persistent field. 898 * 899 * @param name the name of the serializable field 900 * @param val the value to assign to the field 901 * @throws IllegalArgumentException if <code>name</code> does not 902 * match the name of a serializable field for the class whose fields 903 * are being written, or if the type of the named field is not 904 * <code>boolean</code> 905 */ put(String name, boolean val)906 public abstract void put(String name, boolean val); 907 908 /** 909 * Put the value of the named byte field into the persistent field. 910 * 911 * @param name the name of the serializable field 912 * @param val the value to assign to the field 913 * @throws IllegalArgumentException if <code>name</code> does not 914 * match the name of a serializable field for the class whose fields 915 * are being written, or if the type of the named field is not 916 * <code>byte</code> 917 */ put(String name, byte val)918 public abstract void put(String name, byte val); 919 920 /** 921 * Put the value of the named char field into the persistent field. 922 * 923 * @param name the name of the serializable field 924 * @param val the value to assign to the field 925 * @throws IllegalArgumentException if <code>name</code> does not 926 * match the name of a serializable field for the class whose fields 927 * are being written, or if the type of the named field is not 928 * <code>char</code> 929 */ put(String name, char val)930 public abstract void put(String name, char val); 931 932 /** 933 * Put the value of the named short field into the persistent field. 934 * 935 * @param name the name of the serializable field 936 * @param val the value to assign to the field 937 * @throws IllegalArgumentException if <code>name</code> does not 938 * match the name of a serializable field for the class whose fields 939 * are being written, or if the type of the named field is not 940 * <code>short</code> 941 */ put(String name, short val)942 public abstract void put(String name, short val); 943 944 /** 945 * Put the value of the named int field into the persistent field. 946 * 947 * @param name the name of the serializable field 948 * @param val the value to assign to the field 949 * @throws IllegalArgumentException if <code>name</code> does not 950 * match the name of a serializable field for the class whose fields 951 * are being written, or if the type of the named field is not 952 * <code>int</code> 953 */ put(String name, int val)954 public abstract void put(String name, int val); 955 956 /** 957 * Put the value of the named long field into the persistent field. 958 * 959 * @param name the name of the serializable field 960 * @param val the value to assign to the field 961 * @throws IllegalArgumentException if <code>name</code> does not 962 * match the name of a serializable field for the class whose fields 963 * are being written, or if the type of the named field is not 964 * <code>long</code> 965 */ put(String name, long val)966 public abstract void put(String name, long val); 967 968 /** 969 * Put the value of the named float field into the persistent field. 970 * 971 * @param name the name of the serializable field 972 * @param val the value to assign to the field 973 * @throws IllegalArgumentException if <code>name</code> does not 974 * match the name of a serializable field for the class whose fields 975 * are being written, or if the type of the named field is not 976 * <code>float</code> 977 */ put(String name, float val)978 public abstract void put(String name, float val); 979 980 /** 981 * Put the value of the named double field into the persistent field. 982 * 983 * @param name the name of the serializable field 984 * @param val the value to assign to the field 985 * @throws IllegalArgumentException if <code>name</code> does not 986 * match the name of a serializable field for the class whose fields 987 * are being written, or if the type of the named field is not 988 * <code>double</code> 989 */ put(String name, double val)990 public abstract void put(String name, double val); 991 992 /** 993 * Put the value of the named Object field into the persistent field. 994 * 995 * @param name the name of the serializable field 996 * @param val the value to assign to the field 997 * (which may be <code>null</code>) 998 * @throws IllegalArgumentException if <code>name</code> does not 999 * match the name of a serializable field for the class whose fields 1000 * are being written, or if the type of the named field is not a 1001 * reference type 1002 */ put(String name, Object val)1003 public abstract void put(String name, Object val); 1004 1005 /** 1006 * Write the data and fields to the specified ObjectOutput stream, 1007 * which must be the same stream that produced this 1008 * <code>PutField</code> object. 1009 * 1010 * @param out the stream to write the data and fields to 1011 * @throws IOException if I/O errors occur while writing to the 1012 * underlying stream 1013 * @throws IllegalArgumentException if the specified stream is not 1014 * the same stream that produced this <code>PutField</code> 1015 * object 1016 * @deprecated This method does not write the values contained by this 1017 * <code>PutField</code> object in a proper format, and may 1018 * result in corruption of the serialization stream. The 1019 * correct way to write <code>PutField</code> data is by 1020 * calling the {@link java.io.ObjectOutputStream#writeFields()} 1021 * method. 1022 */ 1023 @Deprecated write(ObjectOutput out)1024 public abstract void write(ObjectOutput out) throws IOException; 1025 } 1026 1027 1028 /** 1029 * Returns protocol version in use. 1030 */ getProtocolVersion()1031 int getProtocolVersion() { 1032 return protocol; 1033 } 1034 1035 /** 1036 * Writes string without allowing it to be replaced in stream. Used by 1037 * ObjectStreamClass to write class descriptor type strings. 1038 */ writeTypeString(String str)1039 void writeTypeString(String str) throws IOException { 1040 int handle; 1041 if (str == null) { 1042 writeNull(); 1043 } else if ((handle = handles.lookup(str)) != -1) { 1044 writeHandle(handle); 1045 } else { 1046 writeString(str, false); 1047 } 1048 } 1049 1050 /** 1051 * Verifies that this (possibly subclass) instance can be constructed 1052 * without violating security constraints: the subclass must not override 1053 * security-sensitive non-final methods, or else the 1054 * "enableSubclassImplementation" SerializablePermission is checked. 1055 */ verifySubclass()1056 private void verifySubclass() { 1057 Class<?> cl = getClass(); 1058 if (cl == ObjectOutputStream.class) { 1059 return; 1060 } 1061 SecurityManager sm = System.getSecurityManager(); 1062 if (sm == null) { 1063 return; 1064 } 1065 processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits); 1066 WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue); 1067 Boolean result = Caches.subclassAudits.get(key); 1068 if (result == null) { 1069 result = Boolean.valueOf(auditSubclass(cl)); 1070 Caches.subclassAudits.putIfAbsent(key, result); 1071 } 1072 if (result.booleanValue()) { 1073 return; 1074 } 1075 sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); 1076 } 1077 1078 /** 1079 * Performs reflective checks on given subclass to verify that it doesn't 1080 * override security-sensitive non-final methods. Returns true if subclass 1081 * is "safe", false otherwise. 1082 */ auditSubclass(final Class<?> subcl)1083 private static boolean auditSubclass(final Class<?> subcl) { 1084 Boolean result = AccessController.doPrivileged( 1085 new PrivilegedAction<Boolean>() { 1086 public Boolean run() { 1087 for (Class<?> cl = subcl; 1088 cl != ObjectOutputStream.class; 1089 cl = cl.getSuperclass()) 1090 { 1091 try { 1092 cl.getDeclaredMethod( 1093 "writeUnshared", new Class<?>[] { Object.class }); 1094 return Boolean.FALSE; 1095 } catch (NoSuchMethodException ex) { 1096 } 1097 try { 1098 cl.getDeclaredMethod("putFields", (Class<?>[]) null); 1099 return Boolean.FALSE; 1100 } catch (NoSuchMethodException ex) { 1101 } 1102 } 1103 return Boolean.TRUE; 1104 } 1105 } 1106 ); 1107 return result.booleanValue(); 1108 } 1109 1110 /** 1111 * Clears internal data structures. 1112 */ clear()1113 private void clear() { 1114 subs.clear(); 1115 handles.clear(); 1116 } 1117 1118 /** 1119 * Underlying writeObject/writeUnshared implementation. 1120 */ writeObject0(Object obj, boolean unshared)1121 private void writeObject0(Object obj, boolean unshared) 1122 throws IOException 1123 { 1124 boolean oldMode = bout.setBlockDataMode(false); 1125 depth++; 1126 try { 1127 // handle previously written and non-replaceable objects 1128 int h; 1129 if ((obj = subs.lookup(obj)) == null) { 1130 writeNull(); 1131 return; 1132 } else if (!unshared && (h = handles.lookup(obj)) != -1) { 1133 writeHandle(h); 1134 return; 1135 // BEGIN Android-changed 1136 /* 1137 } else if (obj instanceof Class) { 1138 writeClass((Class) obj, unshared); 1139 return; 1140 } else if (obj instanceof ObjectStreamClass) { 1141 writeClassDesc((ObjectStreamClass) obj, unshared); 1142 return; 1143 */ 1144 // END Android-changed 1145 } 1146 1147 // check for replacement object 1148 Object orig = obj; 1149 Class<?> cl = obj.getClass(); 1150 ObjectStreamClass desc; 1151 1152 // BEGIN Android-changed 1153 /* 1154 for (;;) { 1155 // REMIND: skip this check for strings/arrays? 1156 Class<?> repCl; 1157 desc = ObjectStreamClass.lookup(cl, true); 1158 if (!desc.hasWriteReplaceMethod() || 1159 (obj = desc.invokeWriteReplace(obj)) == null || 1160 (repCl = obj.getClass()) == cl) 1161 { 1162 break; 1163 } 1164 cl = repCl; 1165 desc = ObjectStreamClass.lookup(cl, true); 1166 break; 1167 } 1168 */ 1169 // Do only one replace pass 1170 1171 Class repCl; 1172 desc = ObjectStreamClass.lookup(cl, true); 1173 if (desc.hasWriteReplaceMethod() && 1174 (obj = desc.invokeWriteReplace(obj)) != null && 1175 (repCl = obj.getClass()) != cl) 1176 { 1177 cl = repCl; 1178 desc = ObjectStreamClass.lookup(cl, true); 1179 } 1180 // END Android-changed 1181 1182 if (enableReplace) { 1183 Object rep = replaceObject(obj); 1184 if (rep != obj && rep != null) { 1185 cl = rep.getClass(); 1186 desc = ObjectStreamClass.lookup(cl, true); 1187 } 1188 obj = rep; 1189 } 1190 1191 // if object replaced, run through original checks a second time 1192 if (obj != orig) { 1193 subs.assign(orig, obj); 1194 if (obj == null) { 1195 writeNull(); 1196 return; 1197 } else if (!unshared && (h = handles.lookup(obj)) != -1) { 1198 writeHandle(h); 1199 return; 1200 // BEGIN Android-changed 1201 /* 1202 } else if (obj instanceof Class) { 1203 writeClass((Class) obj, unshared); 1204 return; 1205 } else if (obj instanceof ObjectStreamClass) { 1206 writeClassDesc((ObjectStreamClass) obj, unshared); 1207 return; 1208 */ 1209 // END Android-changed 1210 } 1211 } 1212 1213 // remaining cases 1214 // BEGIN Android-changed 1215 if (obj instanceof Class) { 1216 writeClass((Class) obj, unshared); 1217 } else if (obj instanceof ObjectStreamClass) { 1218 writeClassDesc((ObjectStreamClass) obj, unshared); 1219 // END Android-changed 1220 } else if (obj instanceof String) { 1221 writeString((String) obj, unshared); 1222 } else if (cl.isArray()) { 1223 writeArray(obj, desc, unshared); 1224 } else if (obj instanceof Enum) { 1225 writeEnum((Enum<?>) obj, desc, unshared); 1226 } else if (obj instanceof Serializable) { 1227 writeOrdinaryObject(obj, desc, unshared); 1228 } else { 1229 if (extendedDebugInfo) { 1230 throw new NotSerializableException( 1231 cl.getName() + "\n" + debugInfoStack.toString()); 1232 } else { 1233 throw new NotSerializableException(cl.getName()); 1234 } 1235 } 1236 } finally { 1237 depth--; 1238 bout.setBlockDataMode(oldMode); 1239 } 1240 } 1241 1242 /** 1243 * Writes null code to stream. 1244 */ writeNull()1245 private void writeNull() throws IOException { 1246 bout.writeByte(TC_NULL); 1247 } 1248 1249 /** 1250 * Writes given object handle to stream. 1251 */ writeHandle(int handle)1252 private void writeHandle(int handle) throws IOException { 1253 bout.writeByte(TC_REFERENCE); 1254 bout.writeInt(baseWireHandle + handle); 1255 } 1256 1257 /** 1258 * Writes representation of given class to stream. 1259 */ writeClass(Class<?> cl, boolean unshared)1260 private void writeClass(Class<?> cl, boolean unshared) throws IOException { 1261 bout.writeByte(TC_CLASS); 1262 writeClassDesc(ObjectStreamClass.lookup(cl, true), false); 1263 handles.assign(unshared ? null : cl); 1264 } 1265 1266 /** 1267 * Writes representation of given class descriptor to stream. 1268 */ writeClassDesc(ObjectStreamClass desc, boolean unshared)1269 private void writeClassDesc(ObjectStreamClass desc, boolean unshared) 1270 throws IOException 1271 { 1272 int handle; 1273 if (desc == null) { 1274 writeNull(); 1275 } else if (!unshared && (handle = handles.lookup(desc)) != -1) { 1276 writeHandle(handle); 1277 } else if (desc.isProxy()) { 1278 writeProxyDesc(desc, unshared); 1279 } else { 1280 writeNonProxyDesc(desc, unshared); 1281 } 1282 } 1283 isCustomSubclass()1284 private boolean isCustomSubclass() { 1285 // Return true if this class is a custom subclass of ObjectOutputStream 1286 return getClass().getClassLoader() 1287 != ObjectOutputStream.class.getClassLoader(); 1288 } 1289 1290 /** 1291 * Writes class descriptor representing a dynamic proxy class to stream. 1292 */ writeProxyDesc(ObjectStreamClass desc, boolean unshared)1293 private void writeProxyDesc(ObjectStreamClass desc, boolean unshared) 1294 throws IOException 1295 { 1296 bout.writeByte(TC_PROXYCLASSDESC); 1297 handles.assign(unshared ? null : desc); 1298 1299 Class<?> cl = desc.forClass(); 1300 Class<?>[] ifaces = cl.getInterfaces(); 1301 bout.writeInt(ifaces.length); 1302 for (int i = 0; i < ifaces.length; i++) { 1303 bout.writeUTF(ifaces[i].getName()); 1304 } 1305 1306 bout.setBlockDataMode(true); 1307 if (cl != null && isCustomSubclass()) { 1308 ReflectUtil.checkPackageAccess(cl); 1309 } 1310 annotateProxyClass(cl); 1311 bout.setBlockDataMode(false); 1312 bout.writeByte(TC_ENDBLOCKDATA); 1313 1314 writeClassDesc(desc.getSuperDesc(), false); 1315 } 1316 1317 /** 1318 * Writes class descriptor representing a standard (i.e., not a dynamic 1319 * proxy) class to stream. 1320 */ writeNonProxyDesc(ObjectStreamClass desc, boolean unshared)1321 private void writeNonProxyDesc(ObjectStreamClass desc, boolean unshared) 1322 throws IOException 1323 { 1324 bout.writeByte(TC_CLASSDESC); 1325 handles.assign(unshared ? null : desc); 1326 1327 if (protocol == PROTOCOL_VERSION_1) { 1328 // do not invoke class descriptor write hook with old protocol 1329 desc.writeNonProxy(this); 1330 } else { 1331 writeClassDescriptor(desc); 1332 } 1333 1334 Class<?> cl = desc.forClass(); 1335 bout.setBlockDataMode(true); 1336 if (cl != null && isCustomSubclass()) { 1337 ReflectUtil.checkPackageAccess(cl); 1338 } 1339 annotateClass(cl); 1340 bout.setBlockDataMode(false); 1341 bout.writeByte(TC_ENDBLOCKDATA); 1342 1343 writeClassDesc(desc.getSuperDesc(), false); 1344 } 1345 1346 /** 1347 * Writes given string to stream, using standard or long UTF format 1348 * depending on string length. 1349 */ writeString(String str, boolean unshared)1350 private void writeString(String str, boolean unshared) throws IOException { 1351 handles.assign(unshared ? null : str); 1352 long utflen = bout.getUTFLength(str); 1353 if (utflen <= 0xFFFF) { 1354 bout.writeByte(TC_STRING); 1355 bout.writeUTF(str, utflen); 1356 } else { 1357 bout.writeByte(TC_LONGSTRING); 1358 bout.writeLongUTF(str, utflen); 1359 } 1360 } 1361 1362 /** 1363 * Writes given array object to stream. 1364 */ writeArray(Object array, ObjectStreamClass desc, boolean unshared)1365 private void writeArray(Object array, 1366 ObjectStreamClass desc, 1367 boolean unshared) 1368 throws IOException 1369 { 1370 bout.writeByte(TC_ARRAY); 1371 writeClassDesc(desc, false); 1372 handles.assign(unshared ? null : array); 1373 1374 Class<?> ccl = desc.forClass().getComponentType(); 1375 if (ccl.isPrimitive()) { 1376 if (ccl == Integer.TYPE) { 1377 int[] ia = (int[]) array; 1378 bout.writeInt(ia.length); 1379 bout.writeInts(ia, 0, ia.length); 1380 } else if (ccl == Byte.TYPE) { 1381 byte[] ba = (byte[]) array; 1382 bout.writeInt(ba.length); 1383 bout.write(ba, 0, ba.length, true); 1384 } else if (ccl == Long.TYPE) { 1385 long[] ja = (long[]) array; 1386 bout.writeInt(ja.length); 1387 bout.writeLongs(ja, 0, ja.length); 1388 } else if (ccl == Float.TYPE) { 1389 float[] fa = (float[]) array; 1390 bout.writeInt(fa.length); 1391 bout.writeFloats(fa, 0, fa.length); 1392 } else if (ccl == Double.TYPE) { 1393 double[] da = (double[]) array; 1394 bout.writeInt(da.length); 1395 bout.writeDoubles(da, 0, da.length); 1396 } else if (ccl == Short.TYPE) { 1397 short[] sa = (short[]) array; 1398 bout.writeInt(sa.length); 1399 bout.writeShorts(sa, 0, sa.length); 1400 } else if (ccl == Character.TYPE) { 1401 char[] ca = (char[]) array; 1402 bout.writeInt(ca.length); 1403 bout.writeChars(ca, 0, ca.length); 1404 } else if (ccl == Boolean.TYPE) { 1405 boolean[] za = (boolean[]) array; 1406 bout.writeInt(za.length); 1407 bout.writeBooleans(za, 0, za.length); 1408 } else { 1409 throw new InternalError(); 1410 } 1411 } else { 1412 Object[] objs = (Object[]) array; 1413 int len = objs.length; 1414 bout.writeInt(len); 1415 if (extendedDebugInfo) { 1416 debugInfoStack.push( 1417 "array (class \"" + array.getClass().getName() + 1418 "\", size: " + len + ")"); 1419 } 1420 try { 1421 for (int i = 0; i < len; i++) { 1422 if (extendedDebugInfo) { 1423 debugInfoStack.push( 1424 "element of array (index: " + i + ")"); 1425 } 1426 try { 1427 writeObject0(objs[i], false); 1428 } finally { 1429 if (extendedDebugInfo) { 1430 debugInfoStack.pop(); 1431 } 1432 } 1433 } 1434 } finally { 1435 if (extendedDebugInfo) { 1436 debugInfoStack.pop(); 1437 } 1438 } 1439 } 1440 } 1441 1442 /** 1443 * Writes given enum constant to stream. 1444 */ writeEnum(Enum<?> en, ObjectStreamClass desc, boolean unshared)1445 private void writeEnum(Enum<?> en, 1446 ObjectStreamClass desc, 1447 boolean unshared) 1448 throws IOException 1449 { 1450 bout.writeByte(TC_ENUM); 1451 ObjectStreamClass sdesc = desc.getSuperDesc(); 1452 writeClassDesc((sdesc.forClass() == Enum.class) ? desc : sdesc, false); 1453 handles.assign(unshared ? null : en); 1454 writeString(en.name(), false); 1455 } 1456 1457 /** 1458 * Writes representation of a "ordinary" (i.e., not a String, Class, 1459 * ObjectStreamClass, array, or enum constant) serializable object to the 1460 * stream. 1461 */ writeOrdinaryObject(Object obj, ObjectStreamClass desc, boolean unshared)1462 private void writeOrdinaryObject(Object obj, 1463 ObjectStreamClass desc, 1464 boolean unshared) 1465 throws IOException 1466 { 1467 if (extendedDebugInfo) { 1468 debugInfoStack.push( 1469 (depth == 1 ? "root " : "") + "object (class \"" + 1470 obj.getClass().getName() + "\", " + obj.toString() + ")"); 1471 } 1472 try { 1473 desc.checkSerialize(); 1474 1475 bout.writeByte(TC_OBJECT); 1476 writeClassDesc(desc, false); 1477 handles.assign(unshared ? null : obj); 1478 if (desc.isExternalizable() && !desc.isProxy()) { 1479 writeExternalData((Externalizable) obj); 1480 } else { 1481 writeSerialData(obj, desc); 1482 } 1483 } finally { 1484 if (extendedDebugInfo) { 1485 debugInfoStack.pop(); 1486 } 1487 } 1488 } 1489 1490 /** 1491 * Writes externalizable data of given object by invoking its 1492 * writeExternal() method. 1493 */ writeExternalData(Externalizable obj)1494 private void writeExternalData(Externalizable obj) throws IOException { 1495 PutFieldImpl oldPut = curPut; 1496 curPut = null; 1497 1498 if (extendedDebugInfo) { 1499 debugInfoStack.push("writeExternal data"); 1500 } 1501 SerialCallbackContext oldContext = curContext; 1502 try { 1503 curContext = null; 1504 if (protocol == PROTOCOL_VERSION_1) { 1505 obj.writeExternal(this); 1506 } else { 1507 bout.setBlockDataMode(true); 1508 obj.writeExternal(this); 1509 bout.setBlockDataMode(false); 1510 bout.writeByte(TC_ENDBLOCKDATA); 1511 } 1512 } finally { 1513 curContext = oldContext; 1514 if (extendedDebugInfo) { 1515 debugInfoStack.pop(); 1516 } 1517 } 1518 1519 curPut = oldPut; 1520 } 1521 1522 /** 1523 * Writes instance data for each serializable class of given object, from 1524 * superclass to subclass. 1525 */ writeSerialData(Object obj, ObjectStreamClass desc)1526 private void writeSerialData(Object obj, ObjectStreamClass desc) 1527 throws IOException 1528 { 1529 ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout(); 1530 for (int i = 0; i < slots.length; i++) { 1531 ObjectStreamClass slotDesc = slots[i].desc; 1532 if (slotDesc.hasWriteObjectMethod()) { 1533 PutFieldImpl oldPut = curPut; 1534 curPut = null; 1535 SerialCallbackContext oldContext = curContext; 1536 1537 if (extendedDebugInfo) { 1538 debugInfoStack.push( 1539 "custom writeObject data (class \"" + 1540 slotDesc.getName() + "\")"); 1541 } 1542 try { 1543 curContext = new SerialCallbackContext(obj, slotDesc); 1544 bout.setBlockDataMode(true); 1545 slotDesc.invokeWriteObject(obj, this); 1546 bout.setBlockDataMode(false); 1547 bout.writeByte(TC_ENDBLOCKDATA); 1548 } finally { 1549 curContext.setUsed(); 1550 curContext = oldContext; 1551 if (extendedDebugInfo) { 1552 debugInfoStack.pop(); 1553 } 1554 } 1555 1556 curPut = oldPut; 1557 } else { 1558 defaultWriteFields(obj, slotDesc); 1559 } 1560 } 1561 } 1562 1563 /** 1564 * Fetches and writes values of serializable fields of given object to 1565 * stream. The given class descriptor specifies which field values to 1566 * write, and in which order they should be written. 1567 */ defaultWriteFields(Object obj, ObjectStreamClass desc)1568 private void defaultWriteFields(Object obj, ObjectStreamClass desc) 1569 throws IOException 1570 { 1571 Class<?> cl = desc.forClass(); 1572 if (cl != null && obj != null && !cl.isInstance(obj)) { 1573 throw new ClassCastException(); 1574 } 1575 1576 desc.checkDefaultSerialize(); 1577 1578 int primDataSize = desc.getPrimDataSize(); 1579 if (primVals == null || primVals.length < primDataSize) { 1580 primVals = new byte[primDataSize]; 1581 } 1582 desc.getPrimFieldValues(obj, primVals); 1583 bout.write(primVals, 0, primDataSize, false); 1584 1585 ObjectStreamField[] fields = desc.getFields(false); 1586 Object[] objVals = new Object[desc.getNumObjFields()]; 1587 int numPrimFields = fields.length - objVals.length; 1588 desc.getObjFieldValues(obj, objVals); 1589 for (int i = 0; i < objVals.length; i++) { 1590 if (extendedDebugInfo) { 1591 debugInfoStack.push( 1592 "field (class \"" + desc.getName() + "\", name: \"" + 1593 fields[numPrimFields + i].getName() + "\", type: \"" + 1594 fields[numPrimFields + i].getType() + "\")"); 1595 } 1596 try { 1597 writeObject0(objVals[i], 1598 fields[numPrimFields + i].isUnshared()); 1599 } finally { 1600 if (extendedDebugInfo) { 1601 debugInfoStack.pop(); 1602 } 1603 } 1604 } 1605 } 1606 1607 /** 1608 * Attempts to write to stream fatal IOException that has caused 1609 * serialization to abort. 1610 */ writeFatalException(IOException ex)1611 private void writeFatalException(IOException ex) throws IOException { 1612 /* 1613 * Note: the serialization specification states that if a second 1614 * IOException occurs while attempting to serialize the original fatal 1615 * exception to the stream, then a StreamCorruptedException should be 1616 * thrown (section 2.1). However, due to a bug in previous 1617 * implementations of serialization, StreamCorruptedExceptions were 1618 * rarely (if ever) actually thrown--the "root" exceptions from 1619 * underlying streams were thrown instead. This historical behavior is 1620 * followed here for consistency. 1621 */ 1622 clear(); 1623 boolean oldMode = bout.setBlockDataMode(false); 1624 try { 1625 bout.writeByte(TC_EXCEPTION); 1626 writeObject0(ex, false); 1627 clear(); 1628 } finally { 1629 bout.setBlockDataMode(oldMode); 1630 } 1631 } 1632 1633 /** 1634 * Converts specified span of float values into byte values. 1635 */ 1636 // REMIND: remove once hotspot inlines Float.floatToIntBits floatsToBytes(float[] src, int srcpos, byte[] dst, int dstpos, int nfloats)1637 private static native void floatsToBytes(float[] src, int srcpos, 1638 byte[] dst, int dstpos, 1639 int nfloats); 1640 1641 /** 1642 * Converts specified span of double values into byte values. 1643 */ 1644 // REMIND: remove once hotspot inlines Double.doubleToLongBits doublesToBytes(double[] src, int srcpos, byte[] dst, int dstpos, int ndoubles)1645 private static native void doublesToBytes(double[] src, int srcpos, 1646 byte[] dst, int dstpos, 1647 int ndoubles); 1648 1649 /** 1650 * Default PutField implementation. 1651 */ 1652 private class PutFieldImpl extends PutField { 1653 1654 /** class descriptor describing serializable fields */ 1655 private final ObjectStreamClass desc; 1656 /** primitive field values */ 1657 private final byte[] primVals; 1658 /** object field values */ 1659 private final Object[] objVals; 1660 1661 /** 1662 * Creates PutFieldImpl object for writing fields defined in given 1663 * class descriptor. 1664 */ PutFieldImpl(ObjectStreamClass desc)1665 PutFieldImpl(ObjectStreamClass desc) { 1666 this.desc = desc; 1667 primVals = new byte[desc.getPrimDataSize()]; 1668 objVals = new Object[desc.getNumObjFields()]; 1669 } 1670 put(String name, boolean val)1671 public void put(String name, boolean val) { 1672 Bits.putBoolean(primVals, getFieldOffset(name, Boolean.TYPE), val); 1673 } 1674 put(String name, byte val)1675 public void put(String name, byte val) { 1676 primVals[getFieldOffset(name, Byte.TYPE)] = val; 1677 } 1678 put(String name, char val)1679 public void put(String name, char val) { 1680 Bits.putChar(primVals, getFieldOffset(name, Character.TYPE), val); 1681 } 1682 put(String name, short val)1683 public void put(String name, short val) { 1684 Bits.putShort(primVals, getFieldOffset(name, Short.TYPE), val); 1685 } 1686 put(String name, int val)1687 public void put(String name, int val) { 1688 Bits.putInt(primVals, getFieldOffset(name, Integer.TYPE), val); 1689 } 1690 put(String name, float val)1691 public void put(String name, float val) { 1692 Bits.putFloat(primVals, getFieldOffset(name, Float.TYPE), val); 1693 } 1694 put(String name, long val)1695 public void put(String name, long val) { 1696 Bits.putLong(primVals, getFieldOffset(name, Long.TYPE), val); 1697 } 1698 put(String name, double val)1699 public void put(String name, double val) { 1700 Bits.putDouble(primVals, getFieldOffset(name, Double.TYPE), val); 1701 } 1702 put(String name, Object val)1703 public void put(String name, Object val) { 1704 objVals[getFieldOffset(name, Object.class)] = val; 1705 } 1706 1707 // deprecated in ObjectOutputStream.PutField write(ObjectOutput out)1708 public void write(ObjectOutput out) throws IOException { 1709 /* 1710 * Applications should *not* use this method to write PutField 1711 * data, as it will lead to stream corruption if the PutField 1712 * object writes any primitive data (since block data mode is not 1713 * unset/set properly, as is done in OOS.writeFields()). This 1714 * broken implementation is being retained solely for behavioral 1715 * compatibility, in order to support applications which use 1716 * OOS.PutField.write() for writing only non-primitive data. 1717 * 1718 * Serialization of unshared objects is not implemented here since 1719 * it is not necessary for backwards compatibility; also, unshared 1720 * semantics may not be supported by the given ObjectOutput 1721 * instance. Applications which write unshared objects using the 1722 * PutField API must use OOS.writeFields(). 1723 */ 1724 if (ObjectOutputStream.this != out) { 1725 throw new IllegalArgumentException("wrong stream"); 1726 } 1727 out.write(primVals, 0, primVals.length); 1728 1729 ObjectStreamField[] fields = desc.getFields(false); 1730 int numPrimFields = fields.length - objVals.length; 1731 // REMIND: warn if numPrimFields > 0? 1732 for (int i = 0; i < objVals.length; i++) { 1733 if (fields[numPrimFields + i].isUnshared()) { 1734 throw new IOException("cannot write unshared object"); 1735 } 1736 out.writeObject(objVals[i]); 1737 } 1738 } 1739 1740 /** 1741 * Writes buffered primitive data and object fields to stream. 1742 */ writeFields()1743 void writeFields() throws IOException { 1744 bout.write(primVals, 0, primVals.length, false); 1745 1746 ObjectStreamField[] fields = desc.getFields(false); 1747 int numPrimFields = fields.length - objVals.length; 1748 for (int i = 0; i < objVals.length; i++) { 1749 if (extendedDebugInfo) { 1750 debugInfoStack.push( 1751 "field (class \"" + desc.getName() + "\", name: \"" + 1752 fields[numPrimFields + i].getName() + "\", type: \"" + 1753 fields[numPrimFields + i].getType() + "\")"); 1754 } 1755 try { 1756 writeObject0(objVals[i], 1757 fields[numPrimFields + i].isUnshared()); 1758 } finally { 1759 if (extendedDebugInfo) { 1760 debugInfoStack.pop(); 1761 } 1762 } 1763 } 1764 } 1765 1766 /** 1767 * Returns offset of field with given name and type. A specified type 1768 * of null matches all types, Object.class matches all non-primitive 1769 * types, and any other non-null type matches assignable types only. 1770 * Throws IllegalArgumentException if no matching field found. 1771 */ getFieldOffset(String name, Class<?> type)1772 private int getFieldOffset(String name, Class<?> type) { 1773 ObjectStreamField field = desc.getField(name, type); 1774 if (field == null) { 1775 throw new IllegalArgumentException("no such field " + name + 1776 " with type " + type); 1777 } 1778 return field.getOffset(); 1779 } 1780 } 1781 1782 /** 1783 * Buffered output stream with two modes: in default mode, outputs data in 1784 * same format as DataOutputStream; in "block data" mode, outputs data 1785 * bracketed by block data markers (see object serialization specification 1786 * for details). 1787 */ 1788 private static class BlockDataOutputStream 1789 extends OutputStream implements DataOutput 1790 { 1791 /** maximum data block length */ 1792 private static final int MAX_BLOCK_SIZE = 1024; 1793 /** maximum data block header length */ 1794 private static final int MAX_HEADER_SIZE = 5; 1795 /** (tunable) length of char buffer (for writing strings) */ 1796 private static final int CHAR_BUF_SIZE = 256; 1797 1798 /** buffer for writing general/block data */ 1799 private final byte[] buf = new byte[MAX_BLOCK_SIZE]; 1800 /** buffer for writing block data headers */ 1801 private final byte[] hbuf = new byte[MAX_HEADER_SIZE]; 1802 /** char buffer for fast string writes */ 1803 private final char[] cbuf = new char[CHAR_BUF_SIZE]; 1804 1805 /** block data mode */ 1806 private boolean blkmode = false; 1807 /** current offset into buf */ 1808 private int pos = 0; 1809 1810 /** underlying output stream */ 1811 private final OutputStream out; 1812 /** loopback stream (for data writes that span data blocks) */ 1813 private final DataOutputStream dout; 1814 1815 /** 1816 * Indicates that this stream was closed and that a warning must be logged once if an 1817 * attempt is made to write to it and the underlying stream does not throw an exception. 1818 * 1819 * <p>This will be set back to false when a warning is logged to ensure that the log is not 1820 * flooded with warnings. 1821 * 1822 * http://b/28159133 1823 */ 1824 private boolean warnOnceWhenWriting; 1825 1826 /** 1827 * Creates new BlockDataOutputStream on top of given underlying stream. 1828 * Block data mode is turned off by default. 1829 */ BlockDataOutputStream(OutputStream out)1830 BlockDataOutputStream(OutputStream out) { 1831 this.out = out; 1832 dout = new DataOutputStream(this); 1833 } 1834 1835 /** 1836 * Sets block data mode to the given mode (true == on, false == off) 1837 * and returns the previous mode value. If the new mode is the same as 1838 * the old mode, no action is taken. If the new mode differs from the 1839 * old mode, any buffered data is flushed before switching to the new 1840 * mode. 1841 */ setBlockDataMode(boolean mode)1842 boolean setBlockDataMode(boolean mode) throws IOException { 1843 if (blkmode == mode) { 1844 return blkmode; 1845 } 1846 drain(); 1847 blkmode = mode; 1848 return !blkmode; 1849 } 1850 1851 /** 1852 * Returns true if the stream is currently in block data mode, false 1853 * otherwise. 1854 */ getBlockDataMode()1855 boolean getBlockDataMode() { 1856 return blkmode; 1857 } 1858 1859 /** 1860 * Warns if the stream has been closed. 1861 * 1862 * <p>This is called after data has been written to the underlying stream in order to allow 1863 * the underlying stream to detect and fail if an attempt is made to write to a closed 1864 * stream. That ensures that this will only log a warning if the underlying stream does not 1865 * so it will not log unnecessary warnings. 1866 */ warnIfClosed()1867 private void warnIfClosed() { 1868 if (warnOnceWhenWriting) { 1869 System.logW("The app is relying on undefined behavior. Attempting to write to a" 1870 + " closed ObjectOutputStream could produce corrupt output in a future" 1871 + " release of Android.", new IOException("Stream Closed")); 1872 // Set back to false so no more messages are logged unless the stream is closed 1873 // again. 1874 warnOnceWhenWriting = false; 1875 } 1876 } 1877 1878 /* ----------------- generic output stream methods ----------------- */ 1879 /* 1880 * The following methods are equivalent to their counterparts in 1881 * OutputStream, except that they partition written data into data 1882 * blocks when in block data mode. 1883 */ 1884 write(int b)1885 public void write(int b) throws IOException { 1886 if (pos >= MAX_BLOCK_SIZE) { 1887 drain(); 1888 } 1889 buf[pos++] = (byte) b; 1890 } 1891 write(byte[] b)1892 public void write(byte[] b) throws IOException { 1893 write(b, 0, b.length, false); 1894 } 1895 write(byte[] b, int off, int len)1896 public void write(byte[] b, int off, int len) throws IOException { 1897 write(b, off, len, false); 1898 } 1899 flush()1900 public void flush() throws IOException { 1901 drain(); 1902 out.flush(); 1903 } 1904 close()1905 public void close() throws IOException { 1906 flush(); 1907 out.close(); 1908 warnOnceWhenWriting = true; 1909 } 1910 1911 /** 1912 * Writes specified span of byte values from given array. If copy is 1913 * true, copies the values to an intermediate buffer before writing 1914 * them to underlying stream (to avoid exposing a reference to the 1915 * original byte array). 1916 */ write(byte[] b, int off, int len, boolean copy)1917 void write(byte[] b, int off, int len, boolean copy) 1918 throws IOException 1919 { 1920 if (!(copy || blkmode)) { // write directly 1921 drain(); 1922 out.write(b, off, len); 1923 warnIfClosed(); 1924 return; 1925 } 1926 1927 while (len > 0) { 1928 if (pos >= MAX_BLOCK_SIZE) { 1929 drain(); 1930 } 1931 if (len >= MAX_BLOCK_SIZE && !copy && pos == 0) { 1932 // avoid unnecessary copy 1933 writeBlockHeader(MAX_BLOCK_SIZE); 1934 out.write(b, off, MAX_BLOCK_SIZE); 1935 off += MAX_BLOCK_SIZE; 1936 len -= MAX_BLOCK_SIZE; 1937 } else { 1938 int wlen = Math.min(len, MAX_BLOCK_SIZE - pos); 1939 System.arraycopy(b, off, buf, pos, wlen); 1940 pos += wlen; 1941 off += wlen; 1942 len -= wlen; 1943 } 1944 } 1945 warnIfClosed(); 1946 } 1947 1948 /** 1949 * Writes all buffered data from this stream to the underlying stream, 1950 * but does not flush underlying stream. 1951 */ drain()1952 void drain() throws IOException { 1953 if (pos == 0) { 1954 return; 1955 } 1956 if (blkmode) { 1957 writeBlockHeader(pos); 1958 } 1959 out.write(buf, 0, pos); 1960 pos = 0; 1961 warnIfClosed(); 1962 } 1963 1964 /** 1965 * Writes block data header. Data blocks shorter than 256 bytes are 1966 * prefixed with a 2-byte header; all others start with a 5-byte 1967 * header. 1968 */ writeBlockHeader(int len)1969 private void writeBlockHeader(int len) throws IOException { 1970 if (len <= 0xFF) { 1971 hbuf[0] = TC_BLOCKDATA; 1972 hbuf[1] = (byte) len; 1973 out.write(hbuf, 0, 2); 1974 } else { 1975 hbuf[0] = TC_BLOCKDATALONG; 1976 Bits.putInt(hbuf, 1, len); 1977 out.write(hbuf, 0, 5); 1978 } 1979 warnIfClosed(); 1980 } 1981 1982 1983 /* ----------------- primitive data output methods ----------------- */ 1984 /* 1985 * The following methods are equivalent to their counterparts in 1986 * DataOutputStream, except that they partition written data into data 1987 * blocks when in block data mode. 1988 */ 1989 writeBoolean(boolean v)1990 public void writeBoolean(boolean v) throws IOException { 1991 if (pos >= MAX_BLOCK_SIZE) { 1992 drain(); 1993 } 1994 Bits.putBoolean(buf, pos++, v); 1995 } 1996 writeByte(int v)1997 public void writeByte(int v) throws IOException { 1998 if (pos >= MAX_BLOCK_SIZE) { 1999 drain(); 2000 } 2001 buf[pos++] = (byte) v; 2002 } 2003 writeChar(int v)2004 public void writeChar(int v) throws IOException { 2005 if (pos + 2 <= MAX_BLOCK_SIZE) { 2006 Bits.putChar(buf, pos, (char) v); 2007 pos += 2; 2008 } else { 2009 dout.writeChar(v); 2010 } 2011 } 2012 writeShort(int v)2013 public void writeShort(int v) throws IOException { 2014 if (pos + 2 <= MAX_BLOCK_SIZE) { 2015 Bits.putShort(buf, pos, (short) v); 2016 pos += 2; 2017 } else { 2018 dout.writeShort(v); 2019 } 2020 } 2021 writeInt(int v)2022 public void writeInt(int v) throws IOException { 2023 if (pos + 4 <= MAX_BLOCK_SIZE) { 2024 Bits.putInt(buf, pos, v); 2025 pos += 4; 2026 } else { 2027 dout.writeInt(v); 2028 } 2029 } 2030 writeFloat(float v)2031 public void writeFloat(float v) throws IOException { 2032 if (pos + 4 <= MAX_BLOCK_SIZE) { 2033 Bits.putFloat(buf, pos, v); 2034 pos += 4; 2035 } else { 2036 dout.writeFloat(v); 2037 } 2038 } 2039 writeLong(long v)2040 public void writeLong(long v) throws IOException { 2041 if (pos + 8 <= MAX_BLOCK_SIZE) { 2042 Bits.putLong(buf, pos, v); 2043 pos += 8; 2044 } else { 2045 dout.writeLong(v); 2046 } 2047 } 2048 writeDouble(double v)2049 public void writeDouble(double v) throws IOException { 2050 if (pos + 8 <= MAX_BLOCK_SIZE) { 2051 Bits.putDouble(buf, pos, v); 2052 pos += 8; 2053 } else { 2054 dout.writeDouble(v); 2055 } 2056 } 2057 writeBytes(String s)2058 public void writeBytes(String s) throws IOException { 2059 int endoff = s.length(); 2060 int cpos = 0; 2061 int csize = 0; 2062 for (int off = 0; off < endoff; ) { 2063 if (cpos >= csize) { 2064 cpos = 0; 2065 csize = Math.min(endoff - off, CHAR_BUF_SIZE); 2066 s.getChars(off, off + csize, cbuf, 0); 2067 } 2068 if (pos >= MAX_BLOCK_SIZE) { 2069 drain(); 2070 } 2071 int n = Math.min(csize - cpos, MAX_BLOCK_SIZE - pos); 2072 int stop = pos + n; 2073 while (pos < stop) { 2074 buf[pos++] = (byte) cbuf[cpos++]; 2075 } 2076 off += n; 2077 } 2078 } 2079 writeChars(String s)2080 public void writeChars(String s) throws IOException { 2081 int endoff = s.length(); 2082 for (int off = 0; off < endoff; ) { 2083 int csize = Math.min(endoff - off, CHAR_BUF_SIZE); 2084 s.getChars(off, off + csize, cbuf, 0); 2085 writeChars(cbuf, 0, csize); 2086 off += csize; 2087 } 2088 } 2089 writeUTF(String s)2090 public void writeUTF(String s) throws IOException { 2091 writeUTF(s, getUTFLength(s)); 2092 } 2093 2094 2095 /* -------------- primitive data array output methods -------------- */ 2096 /* 2097 * The following methods write out spans of primitive data values. 2098 * Though equivalent to calling the corresponding primitive write 2099 * methods repeatedly, these methods are optimized for writing groups 2100 * of primitive data values more efficiently. 2101 */ 2102 writeBooleans(boolean[] v, int off, int len)2103 void writeBooleans(boolean[] v, int off, int len) throws IOException { 2104 int endoff = off + len; 2105 while (off < endoff) { 2106 if (pos >= MAX_BLOCK_SIZE) { 2107 drain(); 2108 } 2109 int stop = Math.min(endoff, off + (MAX_BLOCK_SIZE - pos)); 2110 while (off < stop) { 2111 Bits.putBoolean(buf, pos++, v[off++]); 2112 } 2113 } 2114 } 2115 writeChars(char[] v, int off, int len)2116 void writeChars(char[] v, int off, int len) throws IOException { 2117 int limit = MAX_BLOCK_SIZE - 2; 2118 int endoff = off + len; 2119 while (off < endoff) { 2120 if (pos <= limit) { 2121 int avail = (MAX_BLOCK_SIZE - pos) >> 1; 2122 int stop = Math.min(endoff, off + avail); 2123 while (off < stop) { 2124 Bits.putChar(buf, pos, v[off++]); 2125 pos += 2; 2126 } 2127 } else { 2128 dout.writeChar(v[off++]); 2129 } 2130 } 2131 } 2132 writeShorts(short[] v, int off, int len)2133 void writeShorts(short[] v, int off, int len) throws IOException { 2134 int limit = MAX_BLOCK_SIZE - 2; 2135 int endoff = off + len; 2136 while (off < endoff) { 2137 if (pos <= limit) { 2138 int avail = (MAX_BLOCK_SIZE - pos) >> 1; 2139 int stop = Math.min(endoff, off + avail); 2140 while (off < stop) { 2141 Bits.putShort(buf, pos, v[off++]); 2142 pos += 2; 2143 } 2144 } else { 2145 dout.writeShort(v[off++]); 2146 } 2147 } 2148 } 2149 writeInts(int[] v, int off, int len)2150 void writeInts(int[] v, int off, int len) throws IOException { 2151 int limit = MAX_BLOCK_SIZE - 4; 2152 int endoff = off + len; 2153 while (off < endoff) { 2154 if (pos <= limit) { 2155 int avail = (MAX_BLOCK_SIZE - pos) >> 2; 2156 int stop = Math.min(endoff, off + avail); 2157 while (off < stop) { 2158 Bits.putInt(buf, pos, v[off++]); 2159 pos += 4; 2160 } 2161 } else { 2162 dout.writeInt(v[off++]); 2163 } 2164 } 2165 } 2166 writeFloats(float[] v, int off, int len)2167 void writeFloats(float[] v, int off, int len) throws IOException { 2168 int limit = MAX_BLOCK_SIZE - 4; 2169 int endoff = off + len; 2170 while (off < endoff) { 2171 if (pos <= limit) { 2172 int avail = (MAX_BLOCK_SIZE - pos) >> 2; 2173 int chunklen = Math.min(endoff - off, avail); 2174 floatsToBytes(v, off, buf, pos, chunklen); 2175 off += chunklen; 2176 pos += chunklen << 2; 2177 } else { 2178 dout.writeFloat(v[off++]); 2179 } 2180 } 2181 } 2182 writeLongs(long[] v, int off, int len)2183 void writeLongs(long[] v, int off, int len) throws IOException { 2184 int limit = MAX_BLOCK_SIZE - 8; 2185 int endoff = off + len; 2186 while (off < endoff) { 2187 if (pos <= limit) { 2188 int avail = (MAX_BLOCK_SIZE - pos) >> 3; 2189 int stop = Math.min(endoff, off + avail); 2190 while (off < stop) { 2191 Bits.putLong(buf, pos, v[off++]); 2192 pos += 8; 2193 } 2194 } else { 2195 dout.writeLong(v[off++]); 2196 } 2197 } 2198 } 2199 writeDoubles(double[] v, int off, int len)2200 void writeDoubles(double[] v, int off, int len) throws IOException { 2201 int limit = MAX_BLOCK_SIZE - 8; 2202 int endoff = off + len; 2203 while (off < endoff) { 2204 if (pos <= limit) { 2205 int avail = (MAX_BLOCK_SIZE - pos) >> 3; 2206 int chunklen = Math.min(endoff - off, avail); 2207 doublesToBytes(v, off, buf, pos, chunklen); 2208 off += chunklen; 2209 pos += chunklen << 3; 2210 } else { 2211 dout.writeDouble(v[off++]); 2212 } 2213 } 2214 } 2215 2216 /** 2217 * Returns the length in bytes of the UTF encoding of the given string. 2218 */ getUTFLength(String s)2219 long getUTFLength(String s) { 2220 int len = s.length(); 2221 long utflen = 0; 2222 for (int off = 0; off < len; ) { 2223 int csize = Math.min(len - off, CHAR_BUF_SIZE); 2224 s.getChars(off, off + csize, cbuf, 0); 2225 for (int cpos = 0; cpos < csize; cpos++) { 2226 char c = cbuf[cpos]; 2227 if (c >= 0x0001 && c <= 0x007F) { 2228 utflen++; 2229 } else if (c > 0x07FF) { 2230 utflen += 3; 2231 } else { 2232 utflen += 2; 2233 } 2234 } 2235 off += csize; 2236 } 2237 return utflen; 2238 } 2239 2240 /** 2241 * Writes the given string in UTF format. This method is used in 2242 * situations where the UTF encoding length of the string is already 2243 * known; specifying it explicitly avoids a prescan of the string to 2244 * determine its UTF length. 2245 */ writeUTF(String s, long utflen)2246 void writeUTF(String s, long utflen) throws IOException { 2247 if (utflen > 0xFFFFL) { 2248 throw new UTFDataFormatException(); 2249 } 2250 writeShort((int) utflen); 2251 if (utflen == (long) s.length()) { 2252 writeBytes(s); 2253 } else { 2254 writeUTFBody(s); 2255 } 2256 } 2257 2258 /** 2259 * Writes given string in "long" UTF format. "Long" UTF format is 2260 * identical to standard UTF, except that it uses an 8 byte header 2261 * (instead of the standard 2 bytes) to convey the UTF encoding length. 2262 */ writeLongUTF(String s)2263 void writeLongUTF(String s) throws IOException { 2264 writeLongUTF(s, getUTFLength(s)); 2265 } 2266 2267 /** 2268 * Writes given string in "long" UTF format, where the UTF encoding 2269 * length of the string is already known. 2270 */ writeLongUTF(String s, long utflen)2271 void writeLongUTF(String s, long utflen) throws IOException { 2272 writeLong(utflen); 2273 if (utflen == (long) s.length()) { 2274 writeBytes(s); 2275 } else { 2276 writeUTFBody(s); 2277 } 2278 } 2279 2280 /** 2281 * Writes the "body" (i.e., the UTF representation minus the 2-byte or 2282 * 8-byte length header) of the UTF encoding for the given string. 2283 */ writeUTFBody(String s)2284 private void writeUTFBody(String s) throws IOException { 2285 int limit = MAX_BLOCK_SIZE - 3; 2286 int len = s.length(); 2287 for (int off = 0; off < len; ) { 2288 int csize = Math.min(len - off, CHAR_BUF_SIZE); 2289 s.getChars(off, off + csize, cbuf, 0); 2290 for (int cpos = 0; cpos < csize; cpos++) { 2291 char c = cbuf[cpos]; 2292 if (pos <= limit) { 2293 if (c <= 0x007F && c != 0) { 2294 buf[pos++] = (byte) c; 2295 } else if (c > 0x07FF) { 2296 buf[pos + 2] = (byte) (0x80 | ((c >> 0) & 0x3F)); 2297 buf[pos + 1] = (byte) (0x80 | ((c >> 6) & 0x3F)); 2298 buf[pos + 0] = (byte) (0xE0 | ((c >> 12) & 0x0F)); 2299 pos += 3; 2300 } else { 2301 buf[pos + 1] = (byte) (0x80 | ((c >> 0) & 0x3F)); 2302 buf[pos + 0] = (byte) (0xC0 | ((c >> 6) & 0x1F)); 2303 pos += 2; 2304 } 2305 } else { // write one byte at a time to normalize block 2306 if (c <= 0x007F && c != 0) { 2307 write(c); 2308 } else if (c > 0x07FF) { 2309 write(0xE0 | ((c >> 12) & 0x0F)); 2310 write(0x80 | ((c >> 6) & 0x3F)); 2311 write(0x80 | ((c >> 0) & 0x3F)); 2312 } else { 2313 write(0xC0 | ((c >> 6) & 0x1F)); 2314 write(0x80 | ((c >> 0) & 0x3F)); 2315 } 2316 } 2317 } 2318 off += csize; 2319 } 2320 } 2321 } 2322 2323 /** 2324 * Lightweight identity hash table which maps objects to integer handles, 2325 * assigned in ascending order. 2326 */ 2327 private static class HandleTable { 2328 2329 /* number of mappings in table/next available handle */ 2330 private int size; 2331 /* size threshold determining when to expand hash spine */ 2332 private int threshold; 2333 /* factor for computing size threshold */ 2334 private final float loadFactor; 2335 /* maps hash value -> candidate handle value */ 2336 private int[] spine; 2337 /* maps handle value -> next candidate handle value */ 2338 private int[] next; 2339 /* maps handle value -> associated object */ 2340 private Object[] objs; 2341 2342 /** 2343 * Creates new HandleTable with given capacity and load factor. 2344 */ HandleTable(int initialCapacity, float loadFactor)2345 HandleTable(int initialCapacity, float loadFactor) { 2346 this.loadFactor = loadFactor; 2347 spine = new int[initialCapacity]; 2348 next = new int[initialCapacity]; 2349 objs = new Object[initialCapacity]; 2350 threshold = (int) (initialCapacity * loadFactor); 2351 clear(); 2352 } 2353 2354 /** 2355 * Assigns next available handle to given object, and returns handle 2356 * value. Handles are assigned in ascending order starting at 0. 2357 */ assign(Object obj)2358 int assign(Object obj) { 2359 if (size >= next.length) { 2360 growEntries(); 2361 } 2362 if (size >= threshold) { 2363 growSpine(); 2364 } 2365 insert(obj, size); 2366 return size++; 2367 } 2368 2369 /** 2370 * Looks up and returns handle associated with given object, or -1 if 2371 * no mapping found. 2372 */ lookup(Object obj)2373 int lookup(Object obj) { 2374 if (size == 0) { 2375 return -1; 2376 } 2377 int index = hash(obj) % spine.length; 2378 for (int i = spine[index]; i >= 0; i = next[i]) { 2379 if (objs[i] == obj) { 2380 return i; 2381 } 2382 } 2383 return -1; 2384 } 2385 2386 /** 2387 * Resets table to its initial (empty) state. 2388 */ clear()2389 void clear() { 2390 Arrays.fill(spine, -1); 2391 Arrays.fill(objs, 0, size, null); 2392 size = 0; 2393 } 2394 2395 /** 2396 * Returns the number of mappings currently in table. 2397 */ size()2398 int size() { 2399 return size; 2400 } 2401 2402 /** 2403 * Inserts mapping object -> handle mapping into table. Assumes table 2404 * is large enough to accommodate new mapping. 2405 */ insert(Object obj, int handle)2406 private void insert(Object obj, int handle) { 2407 int index = hash(obj) % spine.length; 2408 objs[handle] = obj; 2409 next[handle] = spine[index]; 2410 spine[index] = handle; 2411 } 2412 2413 /** 2414 * Expands the hash "spine" -- equivalent to increasing the number of 2415 * buckets in a conventional hash table. 2416 */ growSpine()2417 private void growSpine() { 2418 spine = new int[(spine.length << 1) + 1]; 2419 threshold = (int) (spine.length * loadFactor); 2420 Arrays.fill(spine, -1); 2421 for (int i = 0; i < size; i++) { 2422 insert(objs[i], i); 2423 } 2424 } 2425 2426 /** 2427 * Increases hash table capacity by lengthening entry arrays. 2428 */ growEntries()2429 private void growEntries() { 2430 int newLength = (next.length << 1) + 1; 2431 int[] newNext = new int[newLength]; 2432 System.arraycopy(next, 0, newNext, 0, size); 2433 next = newNext; 2434 2435 Object[] newObjs = new Object[newLength]; 2436 System.arraycopy(objs, 0, newObjs, 0, size); 2437 objs = newObjs; 2438 } 2439 2440 /** 2441 * Returns hash value for given object. 2442 */ hash(Object obj)2443 private int hash(Object obj) { 2444 return System.identityHashCode(obj) & 0x7FFFFFFF; 2445 } 2446 } 2447 2448 /** 2449 * Lightweight identity hash table which maps objects to replacement 2450 * objects. 2451 */ 2452 private static class ReplaceTable { 2453 2454 /* maps object -> index */ 2455 private final HandleTable htab; 2456 /* maps index -> replacement object */ 2457 private Object[] reps; 2458 2459 /** 2460 * Creates new ReplaceTable with given capacity and load factor. 2461 */ ReplaceTable(int initialCapacity, float loadFactor)2462 ReplaceTable(int initialCapacity, float loadFactor) { 2463 htab = new HandleTable(initialCapacity, loadFactor); 2464 reps = new Object[initialCapacity]; 2465 } 2466 2467 /** 2468 * Enters mapping from object to replacement object. 2469 */ assign(Object obj, Object rep)2470 void assign(Object obj, Object rep) { 2471 int index = htab.assign(obj); 2472 while (index >= reps.length) { 2473 grow(); 2474 } 2475 reps[index] = rep; 2476 } 2477 2478 /** 2479 * Looks up and returns replacement for given object. If no 2480 * replacement is found, returns the lookup object itself. 2481 */ lookup(Object obj)2482 Object lookup(Object obj) { 2483 int index = htab.lookup(obj); 2484 return (index >= 0) ? reps[index] : obj; 2485 } 2486 2487 /** 2488 * Resets table to its initial (empty) state. 2489 */ clear()2490 void clear() { 2491 Arrays.fill(reps, 0, htab.size(), null); 2492 htab.clear(); 2493 } 2494 2495 /** 2496 * Returns the number of mappings currently in table. 2497 */ size()2498 int size() { 2499 return htab.size(); 2500 } 2501 2502 /** 2503 * Increases table capacity. 2504 */ grow()2505 private void grow() { 2506 Object[] newReps = new Object[(reps.length << 1) + 1]; 2507 System.arraycopy(reps, 0, newReps, 0, reps.length); 2508 reps = newReps; 2509 } 2510 } 2511 2512 /** 2513 * Stack to keep debug information about the state of the 2514 * serialization process, for embedding in exception messages. 2515 */ 2516 private static class DebugTraceInfoStack { 2517 private final List<String> stack; 2518 DebugTraceInfoStack()2519 DebugTraceInfoStack() { 2520 stack = new ArrayList<>(); 2521 } 2522 2523 /** 2524 * Removes all of the elements from enclosed list. 2525 */ clear()2526 void clear() { 2527 stack.clear(); 2528 } 2529 2530 /** 2531 * Removes the object at the top of enclosed list. 2532 */ pop()2533 void pop() { 2534 stack.remove(stack.size()-1); 2535 } 2536 2537 /** 2538 * Pushes a String onto the top of enclosed list. 2539 */ push(String entry)2540 void push(String entry) { 2541 stack.add("\t- " + entry); 2542 } 2543 2544 /** 2545 * Returns a string representation of this object 2546 */ toString()2547 public String toString() { 2548 StringBuilder buffer = new StringBuilder(); 2549 if (!stack.isEmpty()) { 2550 for(int i = stack.size(); i > 0; i-- ) { 2551 buffer.append(stack.get(i-1) + ((i != 1) ? "\n" : "")); 2552 } 2553 } 2554 return buffer.toString(); 2555 } 2556 } 2557 2558 } 2559