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