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