1. /*
  2. * @(#)ObjectOutputStream.java 1.80 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.io;
  8. import java.lang.reflect.InvocationTargetException;
  9. import java.util.ArrayList;
  10. import java.util.Arrays;
  11. import java.lang.reflect.InvocationTargetException;
  12. import java.security.AccessController;
  13. /**
  14. * An ObjectOutputStream writes primitive data types and graphs of
  15. * Java objects to an OutputStream. The objects can be read
  16. * (reconstituted) using an ObjectInputStream.
  17. * Persistent storage of objects can be accomplished by using a file for
  18. * the stream.
  19. * If the stream is a network socket stream, the objects can be reconsituted
  20. * on another host or in another process. <p>
  21. *
  22. * Only objects that support the java.io.Serializable interface can be
  23. * written to streams.
  24. *
  25. * The class of each serializable object is encoded including the class
  26. * name and signature of the class, the values of the
  27. * object's fields and arrays, and the closure of any other objects
  28. * referenced from the initial objects. <p>
  29. *
  30. * The method <STRONG>writeObject</STRONG> is used to write an object
  31. * to the stream. Any object, including Strings and arrays, is
  32. * written with writeObject. Multiple objects or primitives can be
  33. * written to the stream. The objects must be read back from the
  34. * corresponding ObjectInputstream with the same types and in the same
  35. * order as they were written.<p>
  36. *
  37. * Primitive data types can also be written to the stream using the
  38. * appropriate methods from DataOutput. Strings can also be written
  39. * using the writeUTF method.<p>
  40. *
  41. * The default serialization mechanism for an object writes the class
  42. * of the object, the class signature, and the values of all
  43. * non-transient and non-static fields. References to other objects
  44. * (except in transient or static fields) cause those objects to be
  45. * written also. Multiple references to a single object are encoded
  46. * using a reference sharing mechanism so that graphs of objects can
  47. * be restored to the same shape as when the original was written. <p>
  48. *
  49. * For example to write an object that can be read by the example in ObjectInputStream: <br>
  50. * <PRE>
  51. * FileOutputStream ostream = new FileOutputStream("t.tmp");
  52. * ObjectOutputStream p = new ObjectOutputStream(ostream);
  53. *
  54. * p.writeInt(12345);
  55. * p.writeObject("Today");
  56. * p.writeObject(new Date());
  57. *
  58. * p.flush();
  59. * ostream.close();
  60. *
  61. * </PRE>
  62. *
  63. * Classes that require special handling during the serialization and deserialization
  64. * process must implement special methods with these exact signatures: <p>
  65. *
  66. * <PRE>
  67. * private void readObject(java.io.ObjectInputStream stream)
  68. * throws IOException, ClassNotFoundException;
  69. * private void writeObject(java.io.ObjectOutputStream stream)
  70. * throws IOException
  71. * </PRE><p>
  72. * The writeObject method is responsible for writing the state of
  73. * the object for its particular class so that the corresponding
  74. * readObject method can restore it.
  75. * The method does not need to concern itself with the
  76. * state belonging to the object's superclasses or subclasses.
  77. * State is saved by writing the individual fields to the ObjectOutputStream
  78. * using the writeObject method or by using the methods for
  79. * primitive data types supported by DataOutput. <p>
  80. *
  81. * Serialization does not write out the fields of any object that does
  82. * not implement the java.io.Serializable interface. Subclasses of
  83. * Objects that are not serializable can be serializable. In this case
  84. * the non-serializable class must have a no-arg constructor to allow
  85. * its fields to be initialized. In this case it is the
  86. * responsibility of the subclass to save and restore the state of the
  87. * non-serializable class. It is frequently the case that the fields
  88. * of that class are accessible (public, package, or protected) or
  89. * that there are get and set methods that can be used to restore the
  90. * state. <p>
  91. *
  92. * Serialization of an object can be prevented by implementing writeObject
  93. * and readObject methods that throw the NotSerializableException.
  94. * The exception will be caught by the ObjectOutputStream and abort the
  95. * serialization process.
  96. *
  97. * Implementing the Externalizable interface allows the object to
  98. * assume complete control over the contents and format of the object's
  99. * serialized form. The methods of the Externalizable interface,
  100. * writeExternal and readExternal, are called to save and restore the
  101. * objects state. When implemented by a class they can write and read
  102. * their own state using all of the methods of ObjectOutput and
  103. * ObjectInput. It is the responsibility of the objects to handle any
  104. * versioning that occurs.
  105. *
  106. * Primitive data, excluding serializable fields and externalizable
  107. * data, is written to the ObjectOutputStream in block-data
  108. * records. A block data record is composed of a header and
  109. * data. The block data header consists of a marker and the
  110. * number of bytes to follow the header. Consecutive primitive data
  111. * writes are merged into one block-data record.
  112. *
  113. * (*) The blocking factor used for a block-data record will
  114. * be 1024 bytes.
  115. *
  116. * (*) Each block-data record will be filled up to 1024 bytes, or be
  117. * written whenever there is a termination of block-data mode.
  118. *
  119. * Calls to the ObjectOutputStream methods writeObject,
  120. * defaultWriteObject and writeFields initially terminate any
  121. * existing block-data record.
  122. *
  123. * @author Roger Riggs
  124. * @version 1.67, 03/02/98
  125. * @see java.io.DataOutput
  126. * @see java.io.ObjectInputStream
  127. * @see java.io.Serializable
  128. * @see java.io.Externalizable
  129. * @see <a href="http://java.sun.com/products/jdk/1.2/docs/guide/serialization/spec/output.doc.html"> Object Serialization Specification, Section 2, Object Output Classes</a>
  130. * @since JDK1.1
  131. */
  132. public class ObjectOutputStream
  133. extends OutputStream
  134. implements ObjectOutput, ObjectStreamConstants
  135. {
  136. /**
  137. * Creates an ObjectOutputStream that writes to the specified OutputStream.
  138. * The stream header is written to the stream. The caller may want to call
  139. * flush immediately so that the corresponding ObjectInputStream can read
  140. * the header immediately.
  141. *
  142. * @exception IOException Any exception thrown by the underlying OutputStream.
  143. */
  144. public ObjectOutputStream(OutputStream out) throws IOException {
  145. enableSubclassImplementation = false;
  146. this.out = out;
  147. dos = new DataOutputStream(this);
  148. buf = new byte[1024]; // allocate buffer
  149. writeStreamHeader();
  150. resetStream();
  151. }
  152. /**
  153. * Provide a way for subclasses that are completely reimplementing
  154. * ObjectOutputStream to not have to allocate private data just used by
  155. * this implementation of ObjectOutputStream.
  156. *
  157. * <p>If there is a security manager installed, this method first calls the
  158. * security manager's <code>checkPermission</code> method with a
  159. * <code>SerializablePermission("enableSubclassImplementation")</code>
  160. * permission to ensure it's ok to enable subclassing.
  161. *
  162. * @exception IOException Thrown if not called by a subclass.
  163. *
  164. * @throws SecurityException
  165. * if a security manager exists and its
  166. * <code>checkPermission</code> method denies
  167. * enabling subclassing.
  168. *
  169. * @see SecurityManager#checkPermission
  170. * @see java.security.SerializablePermission
  171. */
  172. protected ObjectOutputStream() throws IOException, SecurityException {
  173. SecurityManager sm = System.getSecurityManager();
  174. if (sm != null) sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
  175. enableSubclassImplementation = true;
  176. }
  177. /**
  178. * This method is called by trusted subclasses of ObjectInputStream
  179. * that constructed ObjectInputStream using the
  180. * protected no-arg constructor. The subclass is expected to provide
  181. * an override method with the modifier "final".
  182. *
  183. * @see #ObjectOutputStream()
  184. * @see #writeObject(Object)
  185. * @since JDK 1.2
  186. */
  187. protected void writeObjectOverride(Object obj) throws IOException
  188. {
  189. }
  190. /**
  191. * Specify stream protocol version to use when writing the stream.<p>
  192. *
  193. * This routine provides a hook to enable the current version
  194. * of Serialization to write in a format that is backwards
  195. * compatible to a previous version of the stream format.<p>
  196. *
  197. * Every effort will be made to avoid introducing additional
  198. * backwards incompatibilities; however, sometimes there is no
  199. * other alternative.<p>
  200. *
  201. * @param version use ProtocolVersion from java.io.ObjectStreamConstants.
  202. * @exception IllegalStateException Thrown if called after any objects have
  203. * been serialized.
  204. * @exception IllegalArgument if invalid version is passed in.
  205. *
  206. * @see java.io.ObjectStreamConstants#PROTOCOL_VERSION_1
  207. * @see java.io.ObjectStreamConstants#PROTOCOL_VERSION_2
  208. */
  209. public void useProtocolVersion(int version) throws IOException {
  210. if (nextWireOffset != 0)
  211. throw new IllegalStateException("Must call useProtocolVersion before writing any objects to the stream");
  212. switch (version) {
  213. case PROTOCOL_VERSION_1:
  214. useDeprecatedExternalizableFormat = true;
  215. break;
  216. case PROTOCOL_VERSION_2:
  217. break;
  218. default:
  219. throw new IllegalArgumentException("unknown version:" + version);
  220. };
  221. }
  222. /**
  223. * Write the specified object to the ObjectOutputStream.
  224. * The class of the object, the signature of the class, and the values
  225. * of the non-transient and non-static fields of the class and all
  226. * of its supertypes are written. Default serialization for a class can be
  227. * overridden using the writeObject and the readObject methods.
  228. * Objects referenced by this object are written transitively so
  229. * that a complete equivalent graph of objects can be
  230. * reconstructed by an ObjectInputStream. <p>
  231. *
  232. * Exceptions are thrown for
  233. * problems with the OutputStream and for classes that should not be
  234. * serialized. All exceptions are fatal to the OutputStream, which
  235. * is left in an indeterminate state, and it is up to the caller
  236. * to ignore or recover the stream state.
  237. * @exception InvalidClassException Something is wrong with a class used by
  238. * serialization.
  239. * @exception NotSerializableException Some object to be serialized does not
  240. * implement the java.io.Serializable interface.
  241. * @exception IOException Any exception thrown by the underlying OutputStream.
  242. */
  243. public final void writeObject(Object obj)
  244. throws IOException
  245. {
  246. if (enableSubclassImplementation) {
  247. writeObjectOverride(obj);
  248. return;
  249. }
  250. Object prevObject = currentObject;
  251. ObjectStreamClass prevClassDesc = currentClassDesc;
  252. boolean oldBlockDataMode = setBlockData(false);
  253. recursionDepth++;
  254. try {
  255. if (serializeNullAndRepeat(obj, REPLACEABLE))
  256. return;
  257. if (checkSpecialClasses(obj))
  258. return;
  259. currentClassDesc =
  260. ObjectStreamClass.lookupInternal(obj.getClass());
  261. Object altobj = obj;
  262. /* Allow the class to replace the instance to be serialized. */
  263. if (currentClassDesc.isReplaceable()) {
  264. altobj =
  265. ObjectStreamClass.invokeMethod(currentClassDesc.writeReplaceMethod,
  266. obj,
  267. null);
  268. }
  269. /* If the replacment is enabled, give subclasses one chance
  270. * to substitute a new object. If one is substituted,
  271. * recheck for null, repeated refs, and special cased classes
  272. */
  273. if (enableReplace) {
  274. altobj = replaceObject(altobj);
  275. }
  276. /* If the object has been replaced check that the object
  277. * is serializable and recheck for the special cases.
  278. */
  279. if (obj != altobj) {
  280. currentClassDesc = altobj == null ?
  281. null :
  282. ObjectStreamClass.lookupInternal(altobj.getClass());
  283. if (altobj != null && ! (altobj instanceof Serializable)) {
  284. String clname = altobj.getClass().getName();
  285. throw new NotSerializableException(clname);
  286. }
  287. // If the alternate object is already
  288. // serialized just remember the replacement
  289. if (serializeNullAndRepeat(altobj, REPLACEABLE)) {
  290. addReplacement(obj, altobj);
  291. return;
  292. }
  293. /* Add this to the set of replaced objects.
  294. * This must be done before the object is
  295. * serialized so that if the object indirectly
  296. * refers to the original it will be redirected to
  297. * the replacement.
  298. *
  299. * NB: checkSpecialClasses should only call
  300. * serializeNullandRepeat for objects that will not
  301. * recurse.
  302. */
  303. addReplacement(obj, altobj);
  304. if (checkSpecialClasses(altobj))
  305. return;
  306. obj = altobj;
  307. }
  308. if (checkSubstitutableSpecialClasses(obj,
  309. currentClassDesc.forClass()))
  310. return;
  311. /* Write out the object as itself */
  312. outputObject(obj);
  313. } catch (IOException ee) {
  314. if (abortIOException == null) {
  315. try {
  316. /* Prepare to write the exception to the stream.
  317. * End blockdatamode in case it's set
  318. * Write the exception code
  319. * reset the stream to forget all previous objects
  320. * write the exception that occurred
  321. * reset the stream again so subsequent objects won't map to
  322. * the exception or its args.
  323. * Continue below to rethrow the exception.
  324. */
  325. setBlockData(false);
  326. writeCode(TC_EXCEPTION);
  327. resetStream();
  328. setBlockData(false); //added since resetStream set to TRUE.
  329. currentClassDesc =
  330. ObjectStreamClass.lookupInternal(ee.getClass());
  331. this.outputObject(ee); //avoid recursing with writeObject
  332. resetStream();
  333. // Set the pending exception to be rethrown.
  334. abortIOException = ee;
  335. } catch (IOException fatal) {
  336. /* An exception occurred while writing the original exception to
  337. * the stream. The original exception is not complete in
  338. * the stream and recusion would be bad. Supercede the original
  339. * Exception with a StreamCorruptedException using the message
  340. * from this current exception.
  341. */
  342. abortIOException =
  343. new StreamCorruptedException(fatal.getMessage());
  344. }
  345. }
  346. } finally {
  347. /* Restore state of previous call incase this is a nested call */
  348. recursionDepth--;
  349. currentObject = prevObject;
  350. currentClassDesc = prevClassDesc;
  351. setBlockData(oldBlockDataMode);
  352. }
  353. /* If the recursion depth is 0, test for and clear the pending exception.
  354. * If there is a pending exception throw it.
  355. */
  356. IOException pending = abortIOException;
  357. if (recursionDepth == 0)
  358. abortIOException = null;
  359. if (pending != null) {
  360. throw pending;
  361. }
  362. }
  363. /*
  364. * Check for special cases of serializing objects.
  365. * These objects are not subject to replacement.
  366. */
  367. private boolean checkSpecialClasses(Object obj) throws IOException {
  368. /*
  369. * If this is a class, don't allow substitution
  370. */
  371. if (obj instanceof Class) {
  372. outputClass((Class)obj);
  373. return true;
  374. }
  375. if (obj instanceof ObjectStreamClass) {
  376. outputClassDescriptor((ObjectStreamClass)obj);
  377. return true;
  378. }
  379. return false;
  380. }
  381. /*
  382. * Check for special cases of substitutable serializing objects.
  383. * These classes are replaceable.
  384. */
  385. private boolean checkSubstitutableSpecialClasses(Object obj, Class cl)
  386. throws IOException
  387. {
  388. if (cl == String.class) {
  389. outputString((String)obj);
  390. return true;
  391. }
  392. if (cl.isArray()) {
  393. outputArray(obj);
  394. return true;
  395. }
  396. return false;
  397. }
  398. /**
  399. * Write the non-static and non-transient fields of the current class
  400. * to this stream. This may only be called from the writeObject method
  401. * of the class being serialized. It will throw the NotActiveException
  402. * if it is called otherwise.
  403. */
  404. public void defaultWriteObject() throws IOException {
  405. if (currentObject == null || currentClassDesc == null)
  406. throw new NotActiveException("defaultWriteObject");
  407. ObjectStreamField[] fields =
  408. currentClassDesc.getFieldsNoCopy();
  409. if (fields.length > 0) {
  410. boolean prevmode = setBlockData(false);
  411. outputClassFields(currentObject, currentClassDesc.forClass(),
  412. fields);
  413. setBlockData(prevmode);
  414. }
  415. }
  416. /**
  417. * Retrieve the object used to buffer persistent fields to be written to
  418. * the stream. The fields will be written to the stream when writeFields
  419. * method is called.
  420. *
  421. * @since JDK1.2
  422. */
  423. public ObjectOutputStream.PutField putFields() throws IOException {
  424. if (currentObject == null || currentClassDesc == null)
  425. throw new NotActiveException("putFields");
  426. // TBD: check if defaultWriteObject has already been called.
  427. currentPutFields = new ObjectOutputStream.PutFieldImpl(currentClassDesc);
  428. return currentPutFields;
  429. }
  430. /**
  431. * Write the buffered fields to the stream.
  432. *
  433. * @since JDK1.2
  434. * @exception NotActiveException Called when a classes writeObject
  435. * method was not called to write the state of the object.
  436. */
  437. public void writeFields() throws IOException {
  438. if (currentObject == null || currentClassDesc == null || currentPutFields == null)
  439. throw new NotActiveException("writeFields");
  440. boolean prevmode = setBlockData(false);
  441. currentPutFields.write(this);
  442. setBlockData(prevmode);
  443. }
  444. /**
  445. * Reset will disregard the state of any objects already written
  446. * to the stream. The state is reset to be the same as a new
  447. * ObjectOutputStream. The current point in the stream is marked
  448. * as reset so the corresponding ObjectInputStream will be reset
  449. * at the same point. Objects previously written to the stream
  450. * will not be refered to as already being in the stream. They
  451. * will be written to the stream again.
  452. */
  453. public void reset() throws IOException {
  454. if (currentObject != null || currentClassDesc != null)
  455. throw new IOException("Illegal call to reset");
  456. /* Write a reset to the stream. */
  457. setBlockData(false);
  458. writeCode(TC_RESET);
  459. resetStream(); // re-init the stream
  460. abortIOException = null;
  461. }
  462. /*
  463. * Internal reset function to reinitialize the state of the stream.
  464. * Reset state of things changed by using the stream.
  465. */
  466. private void resetStream() throws IOException {
  467. if (wireHandle2Object == null) {
  468. wireHandle2Object = new ArrayList();
  469. wireNextHandle = new int[4];
  470. wireHash2Handle = new int[ (1 << wireHashSizePower) - 1];
  471. } else {
  472. // Storage Optimization for frequent calls to reset method.
  473. // Do not reallocate, only reinitialize.
  474. wireHandle2Object.clear();
  475. for (int i = 0; i < nextWireOffset; i++) {
  476. wireNextHandle[i] = 0;
  477. }
  478. }
  479. nextWireOffset = 0;
  480. Arrays.fill(wireHash2Handle, -1);
  481. if (classDescStack == null)
  482. classDescStack = new Stack();
  483. else
  484. classDescStack.setSize(0);
  485. for (int i = 0; i < nextReplaceOffset; i++)
  486. replaceObjects[i] = null;
  487. nextReplaceOffset = 0;
  488. setBlockData(true); /* Re-enable buffering */
  489. }
  490. /**
  491. * Subclasses may implement this method to allow class data to be stored
  492. * in the stream. By default this method does nothing.
  493. * The corresponding method in ObjectInputStream is resolveClass.
  494. * This method is called exactly once for each unique class in the stream.
  495. * The class name and signature will have already been written to the stream.
  496. * This method may make free use of the ObjectOutputStream to save
  497. * any representation of the class it deems suitable (for example,
  498. * the bytes of the class file). The resolveClass method in the corresponding
  499. * subclass of ObjectInputStream must read and use any data or objects
  500. * written by annotateClass.
  501. *
  502. * @exception IOException Any exception thrown by the underlying OutputStream.
  503. */
  504. protected void annotateClass(Class cl)
  505. throws IOException
  506. {
  507. }
  508. /** This method will allow trusted subclasses of ObjectOutputStream
  509. * to substitute one object for another during
  510. * serialization. Replacing objects is disabled until
  511. * enableReplaceObject is called. The enableReplaceObject method
  512. * checks that the stream requesting to do replacment can be
  513. * trusted. Every reference to serializable objects is passed to
  514. * replaceObject. To insure that the private state of objects is
  515. * not unintentionally exposed only trusted streams may use
  516. * replaceObject. <p>
  517. *
  518. * When a subclass is replacing objects it must insure that either
  519. * a complementary substitution must be made during
  520. * deserialization or that the substituted object is compatible
  521. * with every field where the reference will be stored. Objects
  522. * whose type is not a subclass of the type of the field or array
  523. * element abort the serialization by raising an exception and the
  524. * object is not be stored. <p>
  525. *
  526. * This method is called only once when each object is first encountered.
  527. * All subsequent references to the object will be redirected to the
  528. * new object. This method should return the object to be substituted or
  529. * the original object. <P>
  530. *
  531. * Null can be returned as the object to be substituted, but may
  532. * cause NullReferenceException in classes that contain references
  533. * to the original object since they may be expecting an object
  534. * instead of null.<p>
  535. *
  536. * @exception IOException Any exception thrown by the underlying
  537. * OutputStream.
  538. */
  539. protected Object replaceObject(Object obj)
  540. throws IOException
  541. {
  542. return obj;
  543. }
  544. /**
  545. * Enable the stream to do replacement of objects in the stream.
  546. *
  547. * <p>When enabled, the replaceObject method is called for every object
  548. * being serialized.
  549. *
  550. * <p>If <i>enable</i> is true, and there is a security manager installed,
  551. * this method first calls the
  552. * security manager's <code>checkPermission</code> method with a
  553. * <code>SerializablePermission("enableSubstitution")</code>
  554. * permission to ensure it's ok to
  555. * enable the stream to do replacement of objects in the stream.
  556. *
  557. * @throws SecurityException
  558. * if a security manager exists and its
  559. * <code>checkPermission</code> method denies
  560. * enabling the stream to do replacement of objects in the stream.
  561. *
  562. * @see SecurityManager#checkPermission
  563. * @see java.security.SerializablePermission
  564. */
  565. protected boolean enableReplaceObject(boolean enable)
  566. throws SecurityException
  567. {
  568. boolean previous = enableReplace;
  569. if (enable) {
  570. SecurityManager sm = System.getSecurityManager();
  571. if (sm != null) sm.checkPermission(SUBSTITUTION_PERMISSION);
  572. enableReplace = true;
  573. } else {
  574. enableReplace = false;
  575. }
  576. return previous;
  577. }
  578. /**
  579. * The writeStreamHeader method is provided so subclasses can
  580. * append or prepend their own header to the stream.
  581. * It writes the magic number and version to the stream.
  582. */
  583. protected void writeStreamHeader() throws IOException {
  584. writeShort(STREAM_MAGIC);
  585. writeShort(STREAM_VERSION);
  586. }
  587. /**
  588. * Write a string to the stream.
  589. * Note that since Strings are Objects, writeObject
  590. * will behave identically.
  591. */
  592. private void outputString(String s) throws IOException {
  593. /* Allocate a write handle but don't write it to the stream,
  594. * Write out the code for a string,
  595. * the read can regenerate the same sequence and it saves bytes.
  596. */
  597. assignWireOffset(s);
  598. writeCode(TC_STRING);
  599. writeUTF(s);
  600. }
  601. /* Classes are special, they can not be created during deserialization,
  602. * but the appropriate class can be found.
  603. */
  604. private void outputClass(Class aclass) throws IOException {
  605. writeCode(TC_CLASS);
  606. /* Find the class descriptor and write it out */
  607. ObjectStreamClass v = ObjectStreamClass.lookupInternal(aclass);
  608. if (v == null)
  609. throw new NotSerializableException(aclass.getName());
  610. outputClassDescriptor(v);
  611. assignWireOffset(aclass);
  612. }
  613. /* Write the class descriptor */
  614. private void outputClassDescriptor(ObjectStreamClass classdesc)
  615. throws IOException
  616. {
  617. if (serializeNullAndRepeat(classdesc, NOT_REPLACEABLE))
  618. return;
  619. /* Write out the code for a class
  620. * Write out the class name and its serialVersionUID
  621. */
  622. writeCode(TC_CLASSDESC);
  623. String classname = classdesc.getName();
  624. writeUTF(classname);
  625. writeLong(classdesc.getSerialVersionUID());
  626. /* This is done here to be symetric with the inputClass method
  627. * Since the resolveClassName() method may use the stream.
  628. * The assignments of wirehandles must be done in the same order
  629. */
  630. assignWireOffset(classdesc);
  631. /* Write the version description for this class */
  632. classdesc.write(this);
  633. /* Give subclassers a chance to add the class implementation
  634. * to the stream. Set BlockData mode so any information they
  635. * write can be skipped on reading.
  636. */
  637. boolean prevMode = setBlockData(true);
  638. annotateClass(classdesc.forClass());
  639. setBlockData(prevMode);
  640. writeCode(TC_ENDBLOCKDATA);
  641. /*
  642. * Write out the superclass descriptor of this descriptor
  643. * only if it is for a java.io.Serializable class.
  644. * else write null.
  645. */
  646. ObjectStreamClass superdesc = classdesc.getSuperclass();
  647. outputClassDescriptor(superdesc);
  648. }
  649. /**
  650. * Write an array out. Note that since Arrays are Objects, writeObject(obj)
  651. * will behave identically. <br><br>
  652. * @param o can represent an array of any type/dimension.
  653. */
  654. private void outputArray(Object obj)
  655. throws IOException
  656. {
  657. Class currclass = currentClassDesc.forClass();
  658. /* Write out the code for an array and the name of the class */
  659. writeCode(TC_ARRAY);
  660. outputClassDescriptor(currentClassDesc);
  661. /* Assign the wirehandle for this object and outputArrayValues
  662. * writes the length and the array contents.
  663. */
  664. assignWireOffset(obj);
  665. int i, length;
  666. Class type = currclass.getComponentType();
  667. if (type.isPrimitive()) {
  668. /* Write arrays of primitive types using the DataOutput
  669. * methods that convert each element into the output buffer.
  670. * The data types are ordered by the frequency
  671. * in which they are expected to occur.
  672. */
  673. if (type == Integer.TYPE) {
  674. int[] array = (int[])obj;
  675. length = array.length;
  676. writeInt(length);
  677. for (i = 0; i < length; i++) {
  678. writeInt(array[i]);
  679. }
  680. } else if (type == Byte.TYPE) {
  681. byte[] array = (byte[])obj;
  682. length = array.length;
  683. writeInt(length);
  684. writeInternal(array, 0, length, true);
  685. } else if (type == Long.TYPE) {
  686. long[] array = (long[])obj;
  687. length = array.length;
  688. writeInt(length);
  689. for (i = 0; i < length; i++) {
  690. writeLong(array[i]);
  691. }
  692. } else if (type == Float.TYPE) {
  693. float[] array = (float[])obj;
  694. length = array.length;
  695. writeInt(length);
  696. for (i = 0; i < length; i++) {
  697. writeFloat(array[i]);
  698. }
  699. } else if (type == Double.TYPE) {
  700. double[] array = (double[])obj;
  701. length = array.length;
  702. writeInt(length);
  703. for (i = 0; i < length; i++) {
  704. writeDouble(array[i]);
  705. }
  706. } else if (type == Short.TYPE) {
  707. short[] array = (short[])obj;
  708. length = array.length;
  709. writeInt(length);
  710. for (i = 0; i < length; i++) {
  711. writeShort(array[i]);
  712. }
  713. } else if (type == Character.TYPE) {
  714. char[] array = (char[])obj;
  715. length = array.length;
  716. writeInt(length);
  717. for (i = 0; i < length; i++) {
  718. writeChar(array[i]);
  719. }
  720. } else if (type == Boolean.TYPE) {
  721. boolean[] array = (boolean[])obj;
  722. length = array.length;
  723. writeInt(length);
  724. for (i = 0; i < length; i++) {
  725. writeBoolean(array[i]);
  726. }
  727. } else {
  728. throw new InvalidClassException(currclass.getName());
  729. }
  730. } else {
  731. Object[] array = (Object[])obj;
  732. length = array.length;
  733. writeInt(length);
  734. for (i = 0; i < length; i++) {
  735. writeObject(array[i]);
  736. }
  737. }
  738. }
  739. /*
  740. * Write a typeString to the stream.
  741. * Do not allow replaceObject to be called on typeString.
  742. */
  743. void writeTypeString(String typeString) throws IOException {
  744. int handle = findWireOffset(typeString);
  745. if (handle >= 0) {
  746. writeCode(TC_REFERENCE);
  747. writeInt(handle + baseWireHandle);
  748. } else {
  749. assignWireOffset(typeString);
  750. writeCode(TC_STRING);
  751. writeUTF(typeString);
  752. }
  753. }
  754. /*
  755. * Put the object into the stream The newObject code is written
  756. * followed by the ObjectStreamClass for the object's class. Each
  757. * of the objects classes is written using the default
  758. * serialization code and dispatching to Specials where
  759. * appropriate.
  760. */
  761. private void outputObject(Object obj)
  762. throws IOException
  763. {
  764. currentObject = obj;
  765. if (currentClassDesc.isNonSerializable()) {
  766. throw new NotSerializableException(currentClassDesc.getName());
  767. }
  768. /* Write the code to expect an instance and
  769. * the class descriptor of the instance
  770. */
  771. writeCode(TC_OBJECT);
  772. outputClassDescriptor(currentClassDesc);
  773. /* Assign the next wirehandle */
  774. assignWireOffset(obj);
  775. /* If the object is externalizable,
  776. * call writeExternal.
  777. * else do Serializable processing.
  778. */
  779. if (currentClassDesc.isExternalizable()) {
  780. Externalizable ext = (Externalizable)obj;
  781. if (useDeprecatedExternalizableFormat) {
  782. /* JDK 1.1 external data format.
  783. * Don't write in block data mode and no terminator tag.
  784. */
  785. ext.writeExternal(this);
  786. } else {
  787. /* JDK 1.2 Externalizable data format writes in block data mode
  788. * and terminates externalizable data with TAG_ENDBLOCKDATA.
  789. */
  790. setBlockData(true);
  791. try {
  792. ext.writeExternal(this);
  793. } finally {
  794. setBlockData(false);
  795. writeCode(TC_ENDBLOCKDATA);
  796. }
  797. }
  798. } else {
  799. /* The object's classes should be processed from supertype to subtype
  800. * Push all the clases of the current object onto a stack.
  801. * Remember the stack pointer where this set of classes is being pushed.
  802. */
  803. int stackMark = classDescStack.size();
  804. try {
  805. ObjectStreamClass next;
  806. while ((next = currentClassDesc.getSuperclass()) != null) {
  807. classDescStack.push(currentClassDesc);
  808. currentClassDesc = next;
  809. }
  810. /*
  811. * For currentClassDesc and all the pushed class descriptors
  812. * If the class is writing its own data
  813. * set blockData = true; call the class writeObject method
  814. * If not
  815. * invoke either the defaultWriteObject method.
  816. */
  817. do {
  818. if (currentClassDesc.hasWriteObject()) {
  819. setBlockData(true); /* Block any data the class writes */
  820. invokeObjectWriter(obj);
  821. setBlockData(false);
  822. writeCode(TC_ENDBLOCKDATA);
  823. } else {
  824. defaultWriteObject();
  825. }
  826. } while (classDescStack.size() > stackMark &&
  827. (currentClassDesc = (ObjectStreamClass)classDescStack.pop()) != null);
  828. } finally {
  829. classDescStack.setSize(stackMark);
  830. }
  831. }
  832. }
  833. /*
  834. * Return a replacement for 'forObject', if one exists.
  835. */
  836. private Object lookupReplace(Object obj) {
  837. for (int i = 0; i < nextReplaceOffset; i+= 2) {
  838. if (replaceObjects[i] == obj)
  839. return replaceObjects[i+1];
  840. }
  841. return obj;
  842. }
  843. /* Serialize the reference if it is NULL or is for an object that
  844. * was already replaced or already serialized.
  845. * If the object was already replaced, look for the replacement
  846. * object in the known objects and if found, write its handle
  847. * @param checkForReplace only if true. Enables optimization of
  848. * not checking for replacement of non-replacable objects.
  849. * @returns True if the reference is either null or a repeat.
  850. */
  851. private boolean serializeNullAndRepeat(Object obj, boolean checkForReplace)
  852. throws IOException
  853. {
  854. if (obj == null) {
  855. writeCode(TC_NULL);
  856. return true;
  857. }
  858. /* Look to see if this object has already been replaced.
  859. * If so, proceed using the replacement object.
  860. */
  861. if (checkForReplace && replaceObjects != null) {
  862. obj = lookupReplace(obj);
  863. }
  864. int handle = findWireOffset(obj);
  865. if (handle >= 0) {
  866. /* Add a reference to the stream */
  867. writeCode(TC_REFERENCE);
  868. writeInt(handle + baseWireHandle);
  869. return true;
  870. }
  871. return false; // not serialized, its up to the caller
  872. }
  873. /*
  874. * Locate and return if found the handle for the specified object.
  875. * -1 is returned if the object does not occur in the array of
  876. * known objects.
  877. */
  878. private int findWireOffset(Object obj) {
  879. int hash = System.identityHashCode(obj);
  880. int index = (hash & 0x7FFFFFFF) % wireHash2Handle.length;
  881. for (int handle = wireHash2Handle[index];
  882. handle >= 0;
  883. handle = wireNextHandle[handle]) {
  884. if (wireHandle2Object.get(handle) == obj)
  885. return handle;
  886. }
  887. return -1;
  888. }
  889. /* Allocate a handle for an object.
  890. * The Vector is indexed by the wireHandleOffset
  891. * and contains the object.
  892. * Allow caller to specify the hash method for the object.
  893. */
  894. private void assignWireOffset(Object obj)
  895. throws IOException
  896. {
  897. if (nextWireOffset == wireNextHandle.length) {
  898. int[] oldnexthandles = wireNextHandle;
  899. wireNextHandle = new int[nextWireOffset*2];
  900. System.arraycopy(oldnexthandles, 0,
  901. wireNextHandle, 0,
  902. nextWireOffset);
  903. }
  904. if (nextWireOffset >= wireHashCapacity) {
  905. growWireHash2Handle();
  906. }
  907. wireHandle2Object.add(obj);
  908. hashInsert(obj, nextWireOffset);
  909. nextWireOffset++;
  910. return;
  911. }
  912. private void growWireHash2Handle() {
  913. // double hash table spine.
  914. wireHashSizePower++;
  915. wireHash2Handle = new int[(1 << wireHashSizePower) - 1];
  916. Arrays.fill(wireHash2Handle, -1);
  917. for (int i = 0; i < nextWireOffset; i++) {
  918. wireNextHandle[i] = 0;
  919. }
  920. // refill hash table.
  921. for (int i = 0; i < wireHandle2Object.size(); i++) {
  922. hashInsert(wireHandle2Object.get(i), i);
  923. }
  924. wireHashCapacity = (1 << wireHashSizePower) * wireHashLoadFactor;
  925. }
  926. /*
  927. * Insert the specified object into the hash array and link if
  928. * necessary. Put the new object into the hash table and link the
  929. * previous to it. Newer objects occur earlier in the list.
  930. */
  931. private void hashInsert(Object obj, int offset) {
  932. int hash = System.identityHashCode(obj);
  933. int index = (hash & 0x7FFFFFFF) % wireHash2Handle.length;
  934. wireNextHandle[offset] = wireHash2Handle[index];
  935. wireHash2Handle[index] = offset;
  936. }
  937. /*
  938. * Add a replacement object to the table.
  939. * The even numbered indices are the original objects.
  940. * The odd numbered indices are the replacement objects.
  941. *
  942. */
  943. private void addReplacement(Object orig, Object replacement) {
  944. // Extend the array if there isn't room for this new element
  945. if (replaceObjects == null) {
  946. replaceObjects = new Object[10];
  947. }
  948. if (nextReplaceOffset == replaceObjects.length) {
  949. Object[] oldhandles = replaceObjects;
  950. replaceObjects = new Object[2+nextReplaceOffset*2];
  951. System.arraycopy(oldhandles, 0,
  952. replaceObjects, 0,
  953. nextReplaceOffset);
  954. }
  955. replaceObjects[nextReplaceOffset++] = orig;
  956. replaceObjects[nextReplaceOffset++] = replacement;
  957. }
  958. /* Write out the code indicating the type what follows.
  959. * See ObjectStreamConstants for definitions.
  960. */
  961. private void writeCode(int tag)
  962. throws IOException
  963. {
  964. writeByte(tag);
  965. }
  966. /*
  967. * Implement the OutputStream methods. The stream has
  968. * two modes used internally to ObjectOutputStream. When
  969. * in BlockData mode, all writes are buffered and written
  970. * to the underlying stream prefixed by a code and length.
  971. * When not in BlockData mode (false), writes pass directly
  972. * through to the underlying stream.
  973. * The BlockData mode is used to encapsulate data written
  974. * by class specific writeObject methods that is intended
  975. * only to be read by corresponding readObject method of the
  976. * same class. The blocking of data allows it to be skipped
  977. * if necessary.
  978. *
  979. * The setBlockData method is used to switch buffering
  980. * on and off. When switching between on and off
  981. * the buffer is drained.
  982. *
  983. * The actual buffering is very similar to that of
  984. * BufferedOutputStream but BufferedOutputStream can
  985. * write to the underlying stream without the headers.
  986. */
  987. private boolean blockDataMode; /* true to buffer and block data */
  988. private byte[] buf; /* byte array of buffered data. */
  989. private int count; /* count of bytes in the buffer */
  990. private OutputStream out; /* Stream to write the data to */
  991. /**
  992. * Writes a byte. This method will block until the byte is actually
  993. * written.
  994. * @param b the byte
  995. * @exception IOException If an I/O error has occurred.
  996. */
  997. public void write(int data) throws IOException {
  998. if (count >= buf.length)
  999. drain(); /* Drain, make room for more */
  1000. buf[count++] = (byte)data;
  1001. }
  1002. /**
  1003. * Writes an array of bytes. This method will block until the bytes
  1004. * are actually written.
  1005. * @param b the data to be written
  1006. * @exception IOException If an I/O error has occurred.
  1007. */
  1008. public void write(byte b[]) throws IOException {
  1009. write(b, 0, b.length);
  1010. }
  1011. /*
  1012. * Writes a sub array of bytes.
  1013. * @param b the data to be written
  1014. * @param off the start offset in the data
  1015. * @param len the number of bytes that are written
  1016. * @param copyOnWrite do not expose b to overrides of ObjectStream.write,
  1017. * copy the contents of b to a buffer before writing.
  1018. * @exception IOException If an I/O error has occurred.
  1019. */
  1020. private void writeInternal(byte b[], int off, int len,
  1021. boolean copyOnWrite) throws IOException {
  1022. if (len < 0) {
  1023. throw new NullPointerException();
  1024. } else if ((off < 0) || (off > b.length) || (len < 0) ||
  1025. ((off + len) > b.length) || ((off + len) < 0)) {
  1026. throw new IndexOutOfBoundsException();
  1027. } else if (len == 0) {
  1028. return;
  1029. }
  1030. if (blockDataMode) {
  1031. writeCanonical(b, off, len);
  1032. } else {
  1033. /*
  1034. * If array will fit in output buffer, copy it in there; otherwise,
  1035. * drain anything in the buffer and send it through to underlying
  1036. * output stream directly.
  1037. */
  1038. int avail = buf.length - count;
  1039. if (len <= avail) {
  1040. System.arraycopy(b, off, buf, count, len);
  1041. count += len;
  1042. } else if (copyOnWrite) {
  1043. bufferedWrite(b, off, len);
  1044. } else {
  1045. drain();
  1046. out.write(b, off, len);
  1047. }
  1048. }
  1049. }
  1050. /**
  1051. * Writes a sub array of bytes.
  1052. * @param b the data to be written
  1053. * @param off the start offset in the data
  1054. * @param len the number of bytes that are written
  1055. * @exception IOException If an I/O error has occurred.
  1056. */
  1057. public void write(byte b[], int off, int len) throws IOException {
  1058. writeInternal(b, off, len, false);
  1059. }
  1060. /* Use write buffering of byte[] b to prevent exposure of
  1061. * 'b' reference to untrusted overrides of ObjectOutput.write(byte[]).
  1062. *
  1063. * NOTE: Method is only intended for protecting serializable byte []
  1064. * fields written by default serialization. Thus, it can
  1065. * never get called while in blockDataMode.
  1066. */
  1067. private void bufferedWrite(byte b[], int off, int len) throws IOException {
  1068. int bufAvail = buf.length - count;
  1069. int bytesToWrite = len;
  1070. // Handle case where byte array is larger than available buffer.
  1071. if (bytesToWrite > bufAvail) {
  1072. // Logically: fill rest of 'buf' with 'b' and drain.
  1073. System.arraycopy(b, off, buf, count, bufAvail);
  1074. off += bufAvail;
  1075. bytesToWrite -= bufAvail;
  1076. out.write(buf, 0, buf.length);
  1077. count = 0;
  1078. // Write out buf.length chunks of byte array.
  1079. while (bytesToWrite >= buf.length) {
  1080. System.arraycopy(b, off, buf, 0, buf.length);
  1081. out.write(buf, 0, buf.length);
  1082. off += buf.length;
  1083. bytesToWrite -= buf.length;
  1084. // Optimization: do not modify or access "count" in this loop.
  1085. }
  1086. }
  1087. // Put remainder of byte array b into buffer.
  1088. if (bytesToWrite != 0) {
  1089. System.arraycopy(b, off, buf, count, bytesToWrite);
  1090. count += bytesToWrite;
  1091. }
  1092. }
  1093. /**
  1094. * Flushes the stream. This will write any buffered
  1095. * output bytes and flush through to the underlying stream.
  1096. * @exception IOException If an I/O error has occurred.
  1097. */
  1098. public void flush() throws IOException {
  1099. drain();
  1100. out.flush();
  1101. }
  1102. /**
  1103. * Drain any buffered data in ObjectOutputStream. Similar to flush
  1104. * but does not propagate the flush to the underlaying stream.
  1105. */
  1106. protected void drain() throws IOException {
  1107. /*
  1108. * Drain the data buffer.
  1109. * If the blocking mode is on, prepend the buffer
  1110. * with the code for a blocked data and the length.
  1111. * The code is TC_BLOCKDATA and the length is < 255 so it fits
  1112. * in a byte.
  1113. */
  1114. if (count == 0)
  1115. return;
  1116. if (blockDataMode)
  1117. writeBlockDataHeader(count);
  1118. out.write(buf, 0, count);
  1119. count = 0;
  1120. }
  1121. /**
  1122. * Closes the stream. This method must be called
  1123. * to release any resources associated with the
  1124. * stream.
  1125. * @exception IOException If an I/O error has occurred.
  1126. */
  1127. public void close() throws IOException {
  1128. flush(); /* Make sure we're not holding any data */
  1129. out.close();
  1130. }
  1131. /*
  1132. * Set the blockData mode, if it turned from on to off
  1133. * the buffer is drained. The previous mode is returned.
  1134. */
  1135. private boolean setBlockData(boolean mode) throws IOException {
  1136. if (blockDataMode == mode)
  1137. return mode;
  1138. drain();
  1139. blockDataMode = mode;
  1140. return !mode; /* previous value was the opposite */
  1141. }
  1142. /* Write the Block-data marker and the length of the data to follow
  1143. * to stream 'out'. If the length is < 256, use the short header form.
  1144. * othewise use the long form.
  1145. */
  1146. private void writeBlockDataHeader(int len) throws IOException {
  1147. if (len <= 255) {
  1148. out.write(TC_BLOCKDATA);
  1149. out.write((byte)len);
  1150. } else {
  1151. // use block data with int size if necessary
  1152. out.write(TC_BLOCKDATALONG);
  1153. // send 32 bit int directly to underlying stream
  1154. out.write((byte)((len >> 24) & 0xFF));
  1155. out.write((byte)((len >> 16) & 0xFF));
  1156. out.write((byte)((len >> 8) & 0xFF));
  1157. out.write((byte)(len & 0xFF));
  1158. }
  1159. }
  1160. /* Canonical form requires constant blocking factor. Write data
  1161. * in b array in constant block-data chunks.
  1162. *
  1163. * Assumes only called when blockDataMode is true.
  1164. */
  1165. private void writeCanonical(byte b[], int off, int len)
  1166. throws IOException
  1167. {
  1168. int bufAvail = buf.length - count;
  1169. int bytesToWrite = len;
  1170. // Handle case where byte array is larger than available buffer.
  1171. if (bytesToWrite > bufAvail) {
  1172. // Logically: fill rest of 'buf' with 'b' and drain.
  1173. // Optimization: avoid copying to 'buf', write partial 'buf' and partial
  1174. // 'b' directly to 'out'.
  1175. writeBlockDataHeader(buf.length);
  1176. out.write(buf, 0, count);
  1177. out.write(b, off, bufAvail);
  1178. count = 0;
  1179. off += bufAvail;
  1180. bytesToWrite -= bufAvail;
  1181. // Optimization: write 'buf.length' BlockData directly to stream.
  1182. while (bytesToWrite >= buf.length) {
  1183. if (blockDataMode)
  1184. writeBlockDataHeader(buf.length);
  1185. out.write(b, off, buf.length);
  1186. off += buf.length;
  1187. bytesToWrite -= buf.length;
  1188. }
  1189. }
  1190. // Put remainder of byte array into buffer.
  1191. if (bytesToWrite != 0) {
  1192. System.arraycopy(b, off, buf, count, bytesToWrite);
  1193. count += bytesToWrite;
  1194. }
  1195. }
  1196. /* -------------------------------------------------------------- */
  1197. /*
  1198. * Provide the methods to implement DataOutput.
  1199. * These are copied from DataOutputStream to avoid the overhead
  1200. * of multiple method calls and to buffer the data directly.
  1201. */
  1202. private DataOutputStream dos;
  1203. /**
  1204. * Writes a boolean.
  1205. * @param data the boolean to be written
  1206. */
  1207. public void writeBoolean(boolean data) throws IOException {
  1208. if (count >= buf.length)
  1209. drain();
  1210. buf[count++] = (byte)(data ? 1 : 0);
  1211. }
  1212. /**
  1213. * Writes an 8 bit byte.
  1214. * @param data the byte value to be written
  1215. */
  1216. public void writeByte(int data) throws IOException {
  1217. if (count >= buf.length)
  1218. drain();
  1219. buf[count++] = (byte)data;
  1220. }
  1221. /**
  1222. * Writes a 16 bit short.
  1223. * @param data the short value to be written
  1224. */
  1225. public void writeShort(int data) throws IOException {
  1226. if (count + 2 > buf.length) {
  1227. if (blockDataMode) {
  1228. // normalize block-data record by writing a byte at a time.
  1229. dos.writeShort(data);
  1230. return;
  1231. } else {
  1232. drain();
  1233. }
  1234. }
  1235. buf[count++] = (byte)((data >>> 8));
  1236. buf[count++] = (byte)((data >>> 0));
  1237. }
  1238. /**
  1239. * Writes a 16 bit char.
  1240. * @param data the char value to be written
  1241. */
  1242. public void writeChar(int data) throws IOException {
  1243. if (count + 2 > buf.length) {
  1244. if (blockDataMode) {
  1245. // normalize block-data record by writing a byte at a time.
  1246. dos.writeChar(data);
  1247. return;
  1248. } else {
  1249. drain();
  1250. }
  1251. }
  1252. buf[count++] = (byte)((data >>> 8));
  1253. buf[count++] = (byte)((data >>> 0));
  1254. }
  1255. /**
  1256. * Writes a 32 bit int.
  1257. * @param data the integer value to be written
  1258. */
  1259. public void writeInt(int data) throws IOException {
  1260. if (count + 4 > buf.length) {
  1261. if (blockDataMode) {
  1262. // normalize block-data record by writing a byte at a time.
  1263. dos.writeInt(data);
  1264. return;
  1265. } else {
  1266. drain();
  1267. }
  1268. }
  1269. buf[count++] = (byte)((data >>> 24));
  1270. buf[count++] = (byte)((data >>> 16));
  1271. buf[count++] = (byte)((data >>> 8));
  1272. buf[count++] = (byte)((data >>> 0));
  1273. }
  1274. /**
  1275. * Writes a 64 bit long.
  1276. * @param data the long value to be written
  1277. */
  1278. public void writeLong(long data) throws IOException {
  1279. if (count + 8 > buf.length) {
  1280. if (blockDataMode) {
  1281. // normalize block-data record by writing a byte at a time.
  1282. dos.writeLong(data);
  1283. return;
  1284. } else {
  1285. drain();
  1286. }
  1287. }
  1288. buf[count++] = (byte)((int)(data >>> 56));
  1289. buf[count++] = (byte)((int)(data >>> 48));
  1290. buf[count++] = (byte)((int)(data >>> 40));
  1291. buf[count++] = (byte)((int)(data >>> 32));
  1292. buf[count++] = (byte)((data >>> 24));
  1293. buf[count++] = (byte)((data >>> 16));
  1294. buf[count++] = (byte)((data >>> 8));
  1295. buf[count++] = (byte)((data >>> 0));
  1296. }
  1297. /**
  1298. * Writes a 32 bit float.
  1299. * @param data the float value to be written
  1300. */
  1301. public void writeFloat(float data) throws IOException {
  1302. int value = Float.floatToIntBits(data);
  1303. if (count + 4 > buf.length) {
  1304. if (blockDataMode) {
  1305. // normalize block-data record by writing a byte at a time.
  1306. dos.writeFloat(data);
  1307. return;
  1308. } else {
  1309. drain();
  1310. }
  1311. }
  1312. buf[count++] = (byte)((value >>> 24));
  1313. buf[count++] = (byte)((value >>> 16));
  1314. buf[count++] = (byte)((value >>> 8));
  1315. buf[count++] = (byte)((value >>> 0));
  1316. }
  1317. /**
  1318. * Writes a 64 bit double.
  1319. * @param data the double value to be written
  1320. */
  1321. public void writeDouble(double data) throws IOException {
  1322. long value = Double.doubleToLongBits(data);
  1323. if (count + 8 > buf.length) {
  1324. if (blockDataMode) {
  1325. // normalize block-data record by writing a byte at a time.
  1326. dos.writeDouble(data);
  1327. return;
  1328. } else {
  1329. drain();
  1330. }
  1331. }
  1332. buf[count++] = (byte)((int)(value >>> 56));
  1333. buf[count++] = (byte)((int)(value >>> 48));
  1334. buf[count++] = (byte)((int)(value >>> 40));
  1335. buf[count++] = (byte)((int)(value >>> 32));
  1336. buf[count++] = (byte)((value >>> 24));
  1337. buf[count++] = (byte)((value >>> 16));
  1338. buf[count++] = (byte)((value >>> 8));
  1339. buf[count++] = (byte)((value >>> 0));
  1340. }
  1341. /**
  1342. * Writes a String as a sequence of bytes.
  1343. * @param s the String of bytes to be written
  1344. */
  1345. public void writeBytes(String data) throws IOException {
  1346. dos.writeBytes(data);
  1347. }
  1348. /**
  1349. * Writes a String as a sequence of chars.
  1350. * @param s the String of chars to be written
  1351. */
  1352. public void writeChars(String data) throws IOException {
  1353. dos.writeChars(data);
  1354. }
  1355. /**
  1356. * Primitive data write of this String in UTF format.
  1357. *
  1358. * Note that there is a significant difference between
  1359. * writing a String into the stream as primitive data or
  1360. * as an Object. A String instance written by writeObject
  1361. * is written into the stream as a String initially. Future
  1362. * writeObject() calls write references to the string into
  1363. * the stream.
  1364. *
  1365. * @param str the String in UTF format
  1366. */
  1367. public void writeUTF(String data) throws IOException {
  1368. dos.writeUTF(data);
  1369. }
  1370. /* Write the fields of the specified class by invoking the appropriate
  1371. * write* method on this class.
  1372. */
  1373. private void outputClassFields(Object o, Class cl,
  1374. ObjectStreamField[] fields)
  1375. throws IOException, InvalidClassException {
  1376. for (int i = 0; i < fields.length; i++) {
  1377. if (fields[i].getField() == null)
  1378. throw new InvalidClassException(cl.getName(),
  1379. "Nonexistent field " + fields[i].getName());
  1380. try {
  1381. switch (fields[i].getTypeCode()) {
  1382. case 'B':
  1383. byte byteValue = fields[i].getField().getByte(o);
  1384. writeByte(byteValue);
  1385. break;
  1386. case 'C':
  1387. char charValue = fields[i].getField().getChar(o);
  1388. writeChar(charValue);
  1389. break;
  1390. case 'F':
  1391. float floatValue = fields[i].getField().getFloat(o);
  1392. writeFloat(floatValue);
  1393. break;
  1394. case 'D' :
  1395. double doubleValue = fields[i].getField().getDouble(o);
  1396. writeDouble(doubleValue);
  1397. break;
  1398. case 'I':
  1399. int intValue = fields[i].getField().getInt(o);
  1400. writeInt(intValue);
  1401. break;
  1402. case 'J':
  1403. long longValue = fields[i].getField().getLong(o);
  1404. writeLong(longValue);
  1405. break;
  1406. case 'S':
  1407. short shortValue = fields[i].getField().getShort(o);
  1408. writeShort(shortValue);
  1409. break;
  1410. case 'Z':
  1411. boolean booleanValue = fields[i].getField().getBoolean(o);
  1412. writeBoolean(booleanValue);
  1413. break;
  1414. case '[':
  1415. case 'L':
  1416. Object objectValue = fields[i].getField().get(o);
  1417. writeObject(objectValue);
  1418. break;
  1419. default:
  1420. throw new InvalidClassException(cl.getName());
  1421. }
  1422. } catch (IllegalAccessException e) {
  1423. throw new InvalidClassException(cl.getName(), e.getMessage());
  1424. }
  1425. }
  1426. }
  1427. /*
  1428. * Test if WriteObject method is present, and if so, invoke writer.
  1429. */
  1430. private void invokeObjectWriter(Object obj)
  1431. throws IOException
  1432. {
  1433. try {
  1434. currentClassDesc.writeObjectMethod.invoke(obj, writeObjectArglist);
  1435. } catch (InvocationTargetException e) {
  1436. Throwable t = e.getTargetException();
  1437. if (t instanceof IOException)
  1438. throw (IOException)t;
  1439. else if (t instanceof RuntimeException)
  1440. throw (RuntimeException) t;
  1441. else if (t instanceof Error)
  1442. throw (Error) t;
  1443. else
  1444. throw new Error("interal error");
  1445. } catch (IllegalAccessException e) {
  1446. // cannot happen
  1447. }
  1448. }
  1449. /*************************************/
  1450. /**
  1451. * Provide programatic access to the persistent fields to be written
  1452. * to ObjectOutput.
  1453. *
  1454. * @since JDK 1.2
  1455. */
  1456. static public abstract class PutField {
  1457. /**
  1458. * Put the value of the named boolean field into the persistent field.
  1459. */
  1460. abstract public void put(String name, boolean value);
  1461. /**
  1462. * Put the value of the named char field into the persistent fields.
  1463. */
  1464. abstract public void put(String name, char value);
  1465. /**
  1466. * Put the value of the named byte field into the persistent fields.
  1467. */
  1468. abstract public void put(String name, byte value);
  1469. /**
  1470. * Put the value of the named short field into the persistent fields.
  1471. */
  1472. abstract public void put(String name, short value);
  1473. /**
  1474. * Put the value of the named int field into the persistent fields.
  1475. */
  1476. abstract public void put(String name, int value);
  1477. /**
  1478. * Put the value of the named long field into the persistent fields.
  1479. */
  1480. abstract public void put(String name, long value);
  1481. /**
  1482. * Put the value of the named float field into the persistent fields.
  1483. */
  1484. abstract public void put(String name, float value);
  1485. /**
  1486. * Put the value of the named double field into the persistent field.
  1487. */
  1488. abstract public void put(String name, double value);
  1489. /**
  1490. * Put the value of the named Object field into the persistent field.
  1491. */
  1492. abstract public void put(String name, Object value);
  1493. /**
  1494. * Write the data and fields to the specified ObjectOutput stream.
  1495. */
  1496. abstract public void write(ObjectOutput out) throws IOException;
  1497. };
  1498. /*************************************************************/
  1499. /**
  1500. * Provide access to the persistent fields to be written to the output stream.
  1501. */
  1502. static final class PutFieldImpl extends PutField {
  1503. /**
  1504. * Put the value of the named boolean field into the persistent field.
  1505. */
  1506. public void put(String name, boolean value)
  1507. throws IllegalArgumentException
  1508. {
  1509. ObjectStreamField field = desc.getField(name, Boolean.TYPE);
  1510. if (field == null || field.getType() != Boolean.TYPE)
  1511. throw new IllegalArgumentException("No such boolean field");
  1512. data[field.getOffset()] = (byte)(value ? 1 : 0);
  1513. }
  1514. /**
  1515. * Put the value of the named char field into the persistent fields.
  1516. */
  1517. public void put(String name, char value) {
  1518. ObjectStreamField field = desc.getField(name, Character.TYPE);
  1519. if (field == null || field.getType() != Character.TYPE)
  1520. throw new IllegalArgumentException("No such char field");
  1521. data[field.getOffset()] = (byte)(value >> 8);
  1522. data[field.getOffset()+1] = (byte)(value);
  1523. }
  1524. /**
  1525. * Put the value of the named byte field into the persistent fields.
  1526. */
  1527. public void put(String name, byte value) {
  1528. ObjectStreamField field = desc.getField(name, Byte.TYPE);
  1529. if (field == null || field.getType() != Byte.TYPE)
  1530. throw new IllegalArgumentException("No such byte field");
  1531. data[field.getOffset()] = value;
  1532. }
  1533. /**
  1534. * Put the value of the named short field into the persistent fields.
  1535. */
  1536. public void put(String name, short value) {
  1537. ObjectStreamField field = desc.getField(name, Short.TYPE);
  1538. if (field == null || field.getType() != Short.TYPE)
  1539. throw new IllegalArgumentException("No such short field");
  1540. int loffset = field.getOffset();
  1541. data[loffset] = (byte)(value >> 8);
  1542. data[loffset+1] = (byte)(value);
  1543. }
  1544. /**
  1545. * Put the value of the named int field into the persistent fields.
  1546. */
  1547. public void put(String name, int value) {
  1548. ObjectStreamField field = desc.getField(name, Integer.TYPE);
  1549. if (field == null || field.getType() != Integer.TYPE)
  1550. throw new IllegalArgumentException("No such int field");
  1551. int loffset = field.getOffset();
  1552. data[loffset] = (byte)(value >> 24);
  1553. data[loffset+1] = (byte)(value >> 16);
  1554. data[loffset+2] = (byte)(value >> 8);
  1555. data[loffset+3] = (byte)value;
  1556. }
  1557. /**
  1558. * Put the value of the named long field into the persistent fields.
  1559. */
  1560. public void put(String name, long value) {
  1561. ObjectStreamField field = desc.getField(name, Long.TYPE);
  1562. if (field == null || field.getType() != Long.TYPE)
  1563. throw new IllegalArgumentException("No such long field");
  1564. int loffset = field.getOffset();
  1565. data[loffset] = (byte)(value >> 56);
  1566. data[loffset+1] = (byte)(value >> 48);
  1567. data[loffset+2] = (byte)(value >> 40);
  1568. data[loffset+3] = (byte)(value >> 32);
  1569. data[loffset+4] = (byte)(value >> 24);
  1570. data[loffset+5] = (byte)(value >> 16);
  1571. data[loffset+6] = (byte)(value >> 8);
  1572. data[loffset+7] = (byte)value;
  1573. }
  1574. /**
  1575. * Put the value of the named float field into the persistent fields.
  1576. */
  1577. public void put(String name, float value) {
  1578. int val = Float.floatToIntBits(value);
  1579. ObjectStreamField field = desc.getField(name, Float.TYPE);
  1580. if (field == null || field.getType() != Float.TYPE)
  1581. throw new IllegalArgumentException("No such float field");
  1582. int loffset = field.getOffset();
  1583. data[loffset] = (byte)(val >> 24);
  1584. data[loffset+1] = (byte)(val >> 16);
  1585. data[loffset+2] = (byte)(val >> 8);
  1586. data[loffset+3] = (byte)val;
  1587. }
  1588. /**
  1589. * Put the value of the named double field into the persistent field.
  1590. */
  1591. public void put(String name, double value) {
  1592. long val = Double.doubleToLongBits(value);
  1593. ObjectStreamField field = desc.getField(name, Double.TYPE);
  1594. if (field == null || field.getType() != Double.TYPE)
  1595. throw new IllegalArgumentException("No such double field");
  1596. int loffset = field.getOffset();
  1597. data[loffset] = (byte)(val >> 56);
  1598. data[loffset+1] = (byte)(val >> 48);
  1599. data[loffset+2] = (byte)(val >> 40);
  1600. data[loffset+3] = (byte)(val >> 32);
  1601. data[loffset+4] = (byte)(val >> 24);
  1602. data[loffset+5] = (byte)(val >> 16);
  1603. data[loffset+6] = (byte)(val >> 8);
  1604. data[loffset+7] = (byte)val;
  1605. }
  1606. /**
  1607. * Put the value of the named Object field into the persistent field.
  1608. */
  1609. public void put(String name, Object value) {
  1610. ObjectStreamField field = desc.getField(name, Object.class);
  1611. if (field == null || field.isPrimitive())
  1612. throw new IllegalArgumentException("No such object field");
  1613. objects[field.getOffset()] = value;
  1614. }
  1615. /**
  1616. * Write the data and fields to the specified stream.
  1617. */
  1618. public void write(ObjectOutput out) throws IOException {
  1619. if (data != null)
  1620. out.write(data, 0, data.length);
  1621. if (objects != null) {
  1622. for (int i = 0; i < objects.length; i++)
  1623. out.writeObject(objects[i]);
  1624. }
  1625. }
  1626. /**
  1627. * Create a PutField object for the a Class.
  1628. * Allocate the arrays for primitives and objects.
  1629. */
  1630. PutFieldImpl(ObjectStreamClass descriptor) {
  1631. desc = descriptor;
  1632. if (desc.primBytes > 0)
  1633. data = new byte[desc.primBytes];
  1634. if (desc.objFields > 0)
  1635. objects = new Object[desc.objFields];
  1636. }
  1637. /*
  1638. * The byte array that contains the bytes for the primitive fields.
  1639. * The Object array that contains the objects for the object fields.
  1640. */
  1641. private byte[] data;
  1642. private Object[] objects;
  1643. private ObjectStreamClass desc;
  1644. };
  1645. /*************************************************************/
  1646. /* Remember the first exception that stopped this stream. */
  1647. private IOException abortIOException = null;
  1648. /* Object references are mapped to the wire handles through a hashtable
  1649. * WireHandles are integers generated by the ObjectOutputStream,
  1650. * they need only be unique within a stream.
  1651. * Objects are assigned sequential handles and stored in wireHandle2Object.
  1652. * The handle for an object is its index in wireHandle2Object.
  1653. * Object with the "same" hashcode are chained using wireHash2Handle.
  1654. * The hashcode of objects is used to index through the wireHash2Handle.
  1655. * -1 is the marker for unused cells in wireNextHandle
  1656. */
  1657. private ArrayList wireHandle2Object;
  1658. private int nextWireOffset;
  1659. /* the next five members implement an inline hashtable. */
  1660. private int[] wireHash2Handle; // hash spine
  1661. private int[] wireNextHandle; // next hash bucket entry
  1662. private int wireHashSizePower = 2; // current power of 2 hash table size - 1
  1663. private int wireHashLoadFactor = 7; // avg number of elements per bucket
  1664. private int wireHashCapacity = (1 << wireHashSizePower) * wireHashLoadFactor;
  1665. /* The object is the current object and ClassDescriptor is the current
  1666. * subclass of the object being written. Nesting information is kept
  1667. * on the stack.
  1668. */
  1669. private Object currentObject;
  1670. private ObjectStreamClass currentClassDesc;
  1671. private Stack classDescStack;
  1672. private PutField currentPutFields;
  1673. private Object[] writeObjectArglist = {this};
  1674. /*
  1675. * Flag set to true to allow replaceObject to be called.
  1676. * Set by enableReplaceObject.
  1677. * The array of replaceObjects and the index of the next insertion.
  1678. */
  1679. boolean enableReplace;
  1680. private Object[] replaceObjects;
  1681. private int nextReplaceOffset;
  1682. static final private boolean REPLACEABLE = true;
  1683. static final private boolean NOT_REPLACEABLE = false;
  1684. /* Recursion level, starts at zero and is incremented for each entry
  1685. * to writeObject. Decremented before exit.
  1686. */
  1687. private int recursionDepth = 0;
  1688. /* If true, use JDK 1.1 Externalizable data format. */
  1689. boolean useDeprecatedExternalizableFormat = false;
  1690. /* if true, override writeObject implementation with writeObjectOverride.
  1691. */
  1692. private boolean enableSubclassImplementation;
  1693. /**
  1694. * Unsynchronized Stack.
  1695. */
  1696. static final class Stack extends ArrayList {
  1697. void setSize(int newSize) {
  1698. if (newSize == 0) {
  1699. clear();
  1700. } else {
  1701. int len = size();
  1702. for (int i = len - 1; i >= newSize; i--) {
  1703. remove(i);
  1704. }
  1705. }
  1706. }
  1707. Object push(Object item) {
  1708. add(item);
  1709. return item;
  1710. }
  1711. /**
  1712. * Removes the object at the top of this stack and returns that
  1713. * object as the value of this function.
  1714. *
  1715. * @return The object at the top of this stack (the last item
  1716. * of the <tt>Vector</tt> object).
  1717. * @exception EmptyStackException if this stack is empty.
  1718. */
  1719. Object pop() {
  1720. Object obj;
  1721. int len = size();
  1722. obj = peek();
  1723. remove(len - 1);
  1724. return obj;
  1725. }
  1726. /**
  1727. * Looks at the object at the top of this stack without removing it
  1728. * from the stack.
  1729. *
  1730. * @return the object at the top of this stack (the last item
  1731. * of the <tt>Vector</tt> object).
  1732. * @exception EmptyStackException if this stack is empty.
  1733. */
  1734. Object peek() {
  1735. int len = size();
  1736. if (len == 0)
  1737. throw new java.util.EmptyStackException();
  1738. return get(len - 1);
  1739. }
  1740. }
  1741. };