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