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
27package java.io;
28
29import java.io.ObjectStreamClass.WeakClassKey;
30import java.lang.ref.ReferenceQueue;
31import java.security.AccessController;
32import java.security.PrivilegedAction;
33import java.util.ArrayList;
34import java.util.Arrays;
35import java.util.List;
36import java.util.concurrent.ConcurrentHashMap;
37import java.util.concurrent.ConcurrentMap;
38import static java.io.ObjectStreamClass.processQueue;
39import java.io.SerialCallbackContext;
40
41import sun.reflect.misc.ReflectUtil;
42
43/**
44 * An ObjectOutputStream writes primitive data types and graphs of Java objects
45 * to an OutputStream.  The objects can be read (reconstituted) using an
46 * ObjectInputStream.  Persistent storage of objects can be accomplished by
47 * using a file for the stream.  If the stream is a network socket stream, the
48 * objects can be reconstituted on another host or in another process.
49 *
50 * <p>Only objects that support the java.io.Serializable interface can be
51 * written to streams.  The class of each serializable object is encoded
52 * including the class name and signature of the class, the values of the
53 * object's fields and arrays, and the closure of any other objects referenced
54 * from the initial objects.
55 *
56 * <p>The method writeObject is used to write an object to the stream.  Any
57 * object, including Strings and arrays, is written with writeObject. Multiple
58 * objects or primitives can be written to the stream.  The objects must be
59 * read back from the corresponding ObjectInputstream with the same types and
60 * in the same order as they were written.
61 *
62 * <p>Primitive data types can also be written to the stream using the
63 * appropriate methods from DataOutput. Strings can also be written using the
64 * writeUTF method.
65 *
66 * <p>The default serialization mechanism for an object writes the class of the
67 * object, the class signature, and the values of all non-transient and
68 * non-static fields.  References to other objects (except in transient or
69 * static fields) cause those objects to be written also. Multiple references
70 * to a single object are encoded using a reference sharing mechanism so that
71 * graphs of objects can be restored to the same shape as when the original was
72 * written.
73 *
74 * <p>For example to write an object that can be read by the example in
75 * ObjectInputStream:
76 * <br>
77 * <pre>
78 *      FileOutputStream fos = new FileOutputStream("t.tmp");
79 *      ObjectOutputStream oos = new ObjectOutputStream(fos);
80 *
81 *      oos.writeInt(12345);
82 *      oos.writeObject("Today");
83 *      oos.writeObject(new Date());
84 *
85 *      oos.close();
86 * </pre>
87 *
88 * <p>Classes that require special handling during the serialization and
89 * deserialization process must implement special methods with these exact
90 * signatures:
91 * <br>
92 * <pre>
93 * private void readObject(java.io.ObjectInputStream stream)
94 *     throws IOException, ClassNotFoundException;
95 * private void writeObject(java.io.ObjectOutputStream stream)
96 *     throws IOException
97 * private void readObjectNoData()
98 *     throws ObjectStreamException;
99 * </pre>
100 *
101 * <p>The writeObject method is responsible for writing the state of the object
102 * for its particular class so that the corresponding readObject method can
103 * restore it.  The method does not need to concern itself with the state
104 * belonging to the object's superclasses or subclasses.  State is saved by
105 * writing the individual fields to the ObjectOutputStream using the
106 * writeObject method or by using the methods for primitive data types
107 * supported by DataOutput.
108 *
109 * <p>Serialization does not write out the fields of any object that does not
110 * implement the java.io.Serializable interface.  Subclasses of Objects that
111 * are not serializable can be serializable. In this case the non-serializable
112 * class must have a no-arg constructor to allow its fields to be initialized.
113 * In this case it is the responsibility of the subclass to save and restore
114 * the state of the non-serializable class. It is frequently the case that the
115 * fields of that class are accessible (public, package, or protected) or that
116 * there are get and set methods that can be used to restore the state.
117 *
118 * <p>Serialization of an object can be prevented by implementing writeObject
119 * and readObject methods that throw the NotSerializableException.  The
120 * exception will be caught by the ObjectOutputStream and abort the
121 * serialization process.
122 *
123 * <p>Implementing the Externalizable interface allows the object to assume
124 * complete control over the contents and format of the object's serialized
125 * form.  The methods of the Externalizable interface, writeExternal and
126 * readExternal, are called to save and restore the objects state.  When
127 * implemented by a class they can write and read their own state using all of
128 * the methods of ObjectOutput and ObjectInput.  It is the responsibility of
129 * the objects to handle any versioning that occurs.
130 *
131 * <p>Enum constants are serialized differently than ordinary serializable or
132 * externalizable objects.  The serialized form of an enum constant consists
133 * solely of its name; field values of the constant are not transmitted.  To
134 * serialize an enum constant, ObjectOutputStream writes the string returned by
135 * the constant's name method.  Like other serializable or externalizable
136 * objects, enum constants can function as the targets of back references
137 * appearing subsequently in the serialization stream.  The process by which
138 * enum constants are serialized cannot be customized; any class-specific
139 * writeObject and writeReplace methods defined by enum types are ignored
140 * during serialization.  Similarly, any serialPersistentFields or
141 * serialVersionUID field declarations are also ignored--all enum types have a
142 * fixed serialVersionUID of 0L.
143 *
144 * <p>Primitive data, excluding serializable fields and externalizable data, is
145 * written to the ObjectOutputStream in block-data records. A block data record
146 * is composed of a header and data. The block data header consists of a marker
147 * and the number of bytes to follow the header.  Consecutive primitive data
148 * writes are merged into one block-data record.  The blocking factor used for
149 * a block-data record will be 1024 bytes.  Each block-data record will be
150 * filled up to 1024 bytes, or be written whenever there is a termination of
151 * block-data mode.  Calls to the ObjectOutputStream methods writeObject,
152 * defaultWriteObject and writeFields initially terminate any existing
153 * block-data record.
154 *
155 * @author      Mike Warres
156 * @author      Roger Riggs
157 * @see java.io.DataOutput
158 * @see java.io.ObjectInputStream
159 * @see java.io.Serializable
160 * @see java.io.Externalizable
161 * @see <a href="{@docRoot}openjdk-redirect.html?v=8&path=/platform/serialization/spec/output.html">Object Serialization Specification, Section 2, Object Output Classes</a>
162 * @since       JDK1.1
163 */
164public class ObjectOutputStream
165    extends OutputStream implements ObjectOutput, ObjectStreamConstants
166{
167
168    private static class Caches {
169        /** cache of subclass security audit results */
170        static final ConcurrentMap<WeakClassKey,Boolean> subclassAudits =
171            new ConcurrentHashMap<>();
172
173        /** queue for WeakReferences to audited subclasses */
174        static final ReferenceQueue<Class<?>> subclassAuditsQueue =
175            new ReferenceQueue<>();
176    }
177
178    /** filter stream for handling block data conversion */
179    private final BlockDataOutputStream bout;
180    /** obj -> wire handle map */
181    private final HandleTable handles;
182    /** obj -> replacement obj map */
183    private final ReplaceTable subs;
184    /** stream protocol version */
185    private int protocol = PROTOCOL_VERSION_2;
186    /** recursion depth */
187    private int depth;
188
189    /** buffer for writing primitive field values */
190    private byte[] primVals;
191
192    /** if true, invoke writeObjectOverride() instead of writeObject() */
193    private final boolean enableOverride;
194    /** if true, invoke replaceObject() */
195    private boolean enableReplace;
196
197    // values below valid only during upcalls to writeObject()/writeExternal()
198    /**
199     * Context during upcalls to class-defined writeObject methods; holds
200     * object currently being serialized and descriptor for current class.
201     * Null when not during writeObject upcall.
202     */
203    private SerialCallbackContext curContext;
204    /** current PutField object */
205    private PutFieldImpl curPut;
206
207    /** custom storage for debug trace info */
208    private final DebugTraceInfoStack debugInfoStack;
209
210    /**
211     * value of "sun.io.serialization.extendedDebugInfo" property,
212     * as true or false for extended information about exception's place
213     */
214    private static final boolean extendedDebugInfo = false;
215
216    /**
217     * Creates an ObjectOutputStream that writes to the specified OutputStream.
218     * This constructor writes the serialization stream header to the
219     * underlying stream; callers may wish to flush the stream immediately to
220     * ensure that constructors for receiving ObjectInputStreams will not block
221     * when reading the header.
222     *
223     * <p>If a security manager is installed, this constructor will check for
224     * the "enableSubclassImplementation" SerializablePermission when invoked
225     * directly or indirectly by the constructor of a subclass which overrides
226     * the ObjectOutputStream.putFields or ObjectOutputStream.writeUnshared
227     * methods.
228     *
229     * @param   out output stream to write to
230     * @throws  IOException if an I/O error occurs while writing stream header
231     * @throws  SecurityException if untrusted subclass illegally overrides
232     *          security-sensitive methods
233     * @throws  NullPointerException if <code>out</code> is <code>null</code>
234     * @since   1.4
235     * @see     ObjectOutputStream#ObjectOutputStream()
236     * @see     ObjectOutputStream#putFields()
237     * @see     ObjectInputStream#ObjectInputStream(InputStream)
238     */
239    public ObjectOutputStream(OutputStream out) throws IOException {
240        verifySubclass();
241        bout = new BlockDataOutputStream(out);
242        handles = new HandleTable(10, (float) 3.00);
243        subs = new ReplaceTable(10, (float) 3.00);
244        enableOverride = false;
245        writeStreamHeader();
246        bout.setBlockDataMode(true);
247        if (extendedDebugInfo) {
248            debugInfoStack = new DebugTraceInfoStack();
249        } else {
250            debugInfoStack = null;
251        }
252    }
253
254    /**
255     * Provide a way for subclasses that are completely reimplementing
256     * ObjectOutputStream to not have to allocate private data just used by
257     * this implementation of ObjectOutputStream.
258     *
259     * <p>If there is a security manager installed, this method first calls the
260     * security manager's <code>checkPermission</code> method with a
261     * <code>SerializablePermission("enableSubclassImplementation")</code>
262     * permission to ensure it's ok to enable subclassing.
263     *
264     * @throws  SecurityException if a security manager exists and its
265     *          <code>checkPermission</code> method denies enabling
266     *          subclassing.
267     * @throws  IOException if an I/O error occurs while creating this stream
268     * @see SecurityManager#checkPermission
269     * @see java.io.SerializablePermission
270     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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         */
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         */
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         */
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         */
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         */
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         */
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         */
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         */
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         */
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
1024        public abstract void write(ObjectOutput out) throws IOException;
1025    }
1026
1027
1028    /**
1029     * Returns protocol version in use.
1030     */
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     */
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     */
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     */
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     */
1113    private void clear() {
1114        subs.clear();
1115        handles.clear();
1116    }
1117
1118    /**
1119     * Underlying writeObject/writeUnshared implementation.
1120     */
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     */
1245    private void writeNull() throws IOException {
1246        bout.writeByte(TC_NULL);
1247    }
1248
1249    /**
1250     * Writes given object handle to stream.
1251     */
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     */
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     */
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
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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
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
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         */
1665        PutFieldImpl(ObjectStreamClass desc) {
1666            this.desc = desc;
1667            primVals = new byte[desc.getPrimDataSize()];
1668            objVals = new Object[desc.getNumObjFields()];
1669        }
1670
1671        public void put(String name, boolean val) {
1672            Bits.putBoolean(primVals, getFieldOffset(name, Boolean.TYPE), val);
1673        }
1674
1675        public void put(String name, byte val) {
1676            primVals[getFieldOffset(name, Byte.TYPE)] = val;
1677        }
1678
1679        public void put(String name, char val) {
1680            Bits.putChar(primVals, getFieldOffset(name, Character.TYPE), val);
1681        }
1682
1683        public void put(String name, short val) {
1684            Bits.putShort(primVals, getFieldOffset(name, Short.TYPE), val);
1685        }
1686
1687        public void put(String name, int val) {
1688            Bits.putInt(primVals, getFieldOffset(name, Integer.TYPE), val);
1689        }
1690
1691        public void put(String name, float val) {
1692            Bits.putFloat(primVals, getFieldOffset(name, Float.TYPE), val);
1693        }
1694
1695        public void put(String name, long val) {
1696            Bits.putLong(primVals, getFieldOffset(name, Long.TYPE), val);
1697        }
1698
1699        public void put(String name, double val) {
1700            Bits.putDouble(primVals, getFieldOffset(name, Double.TYPE), val);
1701        }
1702
1703        public void put(String name, Object val) {
1704            objVals[getFieldOffset(name, Object.class)] = val;
1705        }
1706
1707        // deprecated in ObjectOutputStream.PutField
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         */
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         */
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         */
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         */
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         */
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         */
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
1885        public void write(int b) throws IOException {
1886            if (pos >= MAX_BLOCK_SIZE) {
1887                drain();
1888            }
1889            buf[pos++] = (byte) b;
1890        }
1891
1892        public void write(byte[] b) throws IOException {
1893            write(b, 0, b.length, false);
1894        }
1895
1896        public void write(byte[] b, int off, int len) throws IOException {
1897            write(b, off, len, false);
1898        }
1899
1900        public void flush() throws IOException {
1901            drain();
1902            out.flush();
1903        }
1904
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         */
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         */
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         */
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
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
1997        public void writeByte(int v) throws IOException {
1998            if (pos >= MAX_BLOCK_SIZE) {
1999                drain();
2000            }
2001            buf[pos++] = (byte) v;
2002        }
2003
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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         */
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         */
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         */
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         */
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         */
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         */
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         */
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         */
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         */
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         */
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         */
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         */
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         */
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         */
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         */
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         */
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         */
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         */
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         */
2498        int size() {
2499            return htab.size();
2500        }
2501
2502        /**
2503         * Increases table capacity.
2504         */
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
2519        DebugTraceInfoStack() {
2520            stack = new ArrayList<>();
2521        }
2522
2523        /**
2524         * Removes all of the elements from enclosed list.
2525         */
2526        void clear() {
2527            stack.clear();
2528        }
2529
2530        /**
2531         * Removes the object at the top of enclosed list.
2532         */
2533        void pop() {
2534            stack.remove(stack.size()-1);
2535        }
2536
2537        /**
2538         * Pushes a String onto the top of enclosed list.
2539         */
2540        void push(String entry) {
2541            stack.add("\t- " + entry);
2542        }
2543
2544        /**
2545         * Returns a string representation of this object
2546         */
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