1. /*
  2. * @(#)ObjectOutputStream.java 1.108 01/02/09
  3. *
  4. * Copyright 1996-2001 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package java.io;
  11. import java.lang.reflect.InvocationTargetException;
  12. import java.lang.reflect.Proxy;
  13. import java.util.ArrayList;
  14. import java.util.Arrays;
  15. import java.security.AccessController;
  16. /**
  17. * An ObjectOutputStream writes primitive data types and graphs of
  18. * Java objects to an OutputStream. The objects can be read
  19. * (reconstituted) using an ObjectInputStream.
  20. * Persistent storage of objects can be accomplished by using a file for
  21. * the stream.
  22. * If the stream is a network socket stream, the objects can be reconsituted
  23. * on another host or in another process. <p>
  24. *
  25. * Only objects that support the java.io.Serializable interface can be
  26. * written to streams.
  27. *
  28. * The class of each serializable object is encoded including the class
  29. * name and signature of the class, the values of the
  30. * object's fields and arrays, and the closure of any other objects
  31. * referenced from the initial objects. <p>
  32. *
  33. * The method <STRONG>writeObject</STRONG> is used to write an object
  34. * to the stream. Any object, including Strings and arrays, is
  35. * written with writeObject. Multiple objects or primitives can be
  36. * written to the stream. The objects must be read back from the
  37. * corresponding ObjectInputstream with the same types and in the same
  38. * order as they were written.<p>
  39. *
  40. * Primitive data types can also be written to the stream using the
  41. * appropriate methods from DataOutput. Strings can also be written
  42. * using the writeUTF method.<p>
  43. *
  44. * The default serialization mechanism for an object writes the class
  45. * of the object, the class signature, and the values of all
  46. * non-transient and non-static fields. References to other objects
  47. * (except in transient or static fields) cause those objects to be
  48. * written also. Multiple references to a single object are encoded
  49. * using a reference sharing mechanism so that graphs of objects can
  50. * be restored to the same shape as when the original was written. <p>
  51. *
  52. * For example to write an object that can be read by the example in ObjectInputStream: <br>
  53. * <PRE>
  54. * FileOutputStream ostream = new FileOutputStream("t.tmp");
  55. * ObjectOutputStream p = new ObjectOutputStream(ostream);
  56. *
  57. * p.writeInt(12345);
  58. * p.writeObject("Today");
  59. * p.writeObject(new Date());
  60. *
  61. * p.flush();
  62. * ostream.close();
  63. *
  64. * </PRE>
  65. *
  66. * Classes that require special handling during the serialization and deserialization
  67. * process must implement special methods with these exact signatures: <p>
  68. *
  69. * <PRE>
  70. * private void readObject(java.io.ObjectInputStream stream)
  71. * throws IOException, ClassNotFoundException;
  72. * private void writeObject(java.io.ObjectOutputStream stream)
  73. * throws IOException
  74. * </PRE><p>
  75. * The writeObject method is responsible for writing the state of
  76. * the object for its particular class so that the corresponding
  77. * readObject method can restore it.
  78. * The method does not need to concern itself with the
  79. * state belonging to the object's superclasses or subclasses.
  80. * State is saved by writing the individual fields to the ObjectOutputStream
  81. * using the writeObject method or by using the methods for
  82. * primitive data types supported by DataOutput. <p>
  83. *
  84. * Serialization does not write out the fields of any object that does
  85. * not implement the java.io.Serializable interface. Subclasses of
  86. * Objects that are not serializable can be serializable. In this case
  87. * the non-serializable class must have a no-arg constructor to allow
  88. * its fields to be initialized. In this case it is the
  89. * responsibility of the subclass to save and restore the state of the
  90. * non-serializable class. It is frequently the case that the fields
  91. * of that class are accessible (public, package, or protected) or
  92. * that there are get and set methods that can be used to restore the
  93. * state. <p>
  94. *
  95. * Serialization of an object can be prevented by implementing writeObject
  96. * and readObject methods that throw the NotSerializableException.
  97. * The exception will be caught by the ObjectOutputStream and abort the
  98. * serialization process.
  99. *
  100. * Implementing the Externalizable interface allows the object to
  101. * assume complete control over the contents and format of the object's
  102. * serialized form. The methods of the Externalizable interface,
  103. * writeExternal and readExternal, are called to save and restore the
  104. * objects state. When implemented by a class they can write and read
  105. * their own state using all of the methods of ObjectOutput and
  106. * ObjectInput. It is the responsibility of the objects to handle any
  107. * versioning that occurs.
  108. *
  109. * Primitive data, excluding serializable fields and externalizable
  110. * data, is written to the ObjectOutputStream in block-data
  111. * records. A block data record is composed of a header and
  112. * data. The block data header consists of a marker and the
  113. * number of bytes to follow the header. Consecutive primitive data
  114. * writes are merged into one block-data record.
  115. *
  116. * (*) The blocking factor used for a block-data record will
  117. * be 1024 bytes.
  118. *
  119. * (*) Each block-data record will be filled up to 1024 bytes, or be
  120. * written whenever there is a termination of block-data mode.
  121. *
  122. * Calls to the ObjectOutputStream methods writeObject,
  123. * defaultWriteObject and writeFields initially terminate any
  124. * existing block-data record.
  125. *
  126. * @author Roger Riggs
  127. * @version 1.108, 02/09/01
  128. * @see java.io.DataOutput
  129. * @see java.io.ObjectInputStream
  130. * @see java.io.Serializable
  131. * @see java.io.Externalizable
  132. * @see <a href="../../../guide/serialization/spec/output.doc.html"> Object Serialization Specification, Section 2, Object Output Classes</a>
  133. * @since JDK1.1
  134. */
  135. public class ObjectOutputStream
  136. extends OutputStream
  137. implements ObjectOutput, ObjectStreamConstants
  138. {
  139. /**
  140. * Creates an ObjectOutputStream that writes to the specified OutputStream.
  141. * The stream header is written to the stream. The caller may want to call
  142. * flush immediately so that the corresponding ObjectInputStream can read
  143. * the header immediately.
  144. *
  145. * @param out <code>OutputStream</code> to read from
  146. * @exception IOException Any exception thrown by the underlying
  147. * OutputStream.
  148. */
  149. public ObjectOutputStream(OutputStream out) throws IOException {
  150. enableSubclassImplementation = false;
  151. this.out = out;
  152. dos = new DataOutputStream(this);
  153. buf = new byte[1024]; // allocate buffer
  154. writeStreamHeader();
  155. resetStream();
  156. }
  157. /**
  158. * Provide a way for subclasses that are completely reimplementing
  159. * ObjectOutputStream to not have to allocate private data just used by
  160. * this implementation of ObjectOutputStream.
  161. *
  162. * <p>If there is a security manager installed, this method first calls the
  163. * security manager's <code>checkPermission</code> method with a
  164. * <code>SerializablePermission("enableSubclassImplementation")</code>
  165. * permission to ensure it's ok to enable subclassing.
  166. *
  167. * @exception IOException Thrown if not called by a subclass.
  168. *
  169. * @throws SecurityException
  170. * if a security manager exists and its
  171. * <code>checkPermission</code> method denies
  172. * enabling subclassing.
  173. *
  174. * @see SecurityManager#checkPermission
  175. * @see java.io.SerializablePermission
  176. */
  177. protected ObjectOutputStream() throws IOException, SecurityException {
  178. SecurityManager sm = System.getSecurityManager();
  179. if (sm != null) sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
  180. enableSubclassImplementation = true;
  181. }
  182. /**
  183. * Method used by subclasses to override the default writeObject method.
  184. * This method is called by trusted subclasses of ObjectInputStream
  185. * that constructed ObjectInputStream using the
  186. * protected no-arg constructor. The subclass is expected to provide
  187. * an override method with the modifier "final".
  188. *
  189. * @param obj object to be written to the underlying stream
  190. * @throws IOException if there are I/O errors while writing to the
  191. * underlying stream
  192. * @see #ObjectOutputStream()
  193. * @see #writeObject(Object)
  194. * @since 1.2
  195. */
  196. protected void writeObjectOverride(Object obj) throws IOException
  197. {
  198. }
  199. /**
  200. * Specify stream protocol version to use when writing the stream.<p>
  201. *
  202. * This routine provides a hook to enable the current version
  203. * of Serialization to write in a format that is backwards
  204. * compatible to a previous version of the stream format.<p>
  205. *
  206. * Every effort will be made to avoid introducing additional
  207. * backwards incompatibilities; however, sometimes there is no
  208. * other alternative.<p>
  209. *
  210. * @param version use ProtocolVersion from java.io.ObjectStreamConstants.
  211. * @exception IllegalStateException Thrown if called after any objects
  212. * have been serialized.
  213. * @exception IllegalArgumentException if invalid version is passed in.
  214. * @throws IOException if I/O errors occur
  215. *
  216. * @see java.io.ObjectStreamConstants#PROTOCOL_VERSION_1
  217. * @see java.io.ObjectStreamConstants#PROTOCOL_VERSION_2
  218. * @since 1.2
  219. */
  220. public void useProtocolVersion(int version) throws IOException {
  221. if (handleTable.size() != 0) {
  222. throw new IllegalStateException("Must call useProtocolVersion" +
  223. " before writing any objects to the stream");
  224. }
  225. switch (version) {
  226. case PROTOCOL_VERSION_1:
  227. useDeprecatedExternalizableFormat = true;
  228. break;
  229. case PROTOCOL_VERSION_2:
  230. break;
  231. default:
  232. throw new IllegalArgumentException("unknown version:" + version);
  233. };
  234. }
  235. /**
  236. * Write the specified object to the ObjectOutputStream.
  237. * The class of the object, the signature of the class, and the values
  238. * of the non-transient and non-static fields of the class and all
  239. * of its supertypes are written. Default serialization for a class can be
  240. * overridden using the writeObject and the readObject methods.
  241. * Objects referenced by this object are written transitively so
  242. * that a complete equivalent graph of objects can be
  243. * reconstructed by an ObjectInputStream. <p>
  244. *
  245. * Exceptions are thrown for
  246. * problems with the OutputStream and for classes that should not be
  247. * serialized. All exceptions are fatal to the OutputStream, which
  248. * is left in an indeterminate state, and it is up to the caller
  249. * to ignore or recover the stream state.
  250. *
  251. * @exception InvalidClassException Something is wrong with a class used by
  252. * serialization.
  253. * @exception NotSerializableException Some object to be serialized does not
  254. * implement the java.io.Serializable interface.
  255. * @exception IOException Any exception thrown by the underlying OutputStream.
  256. */
  257. public final void writeObject(Object obj)
  258. throws IOException
  259. {
  260. if (enableSubclassImplementation) {
  261. writeObjectOverride(obj);
  262. return;
  263. }
  264. Object prevObject = currentObject;
  265. ObjectStreamClass prevClassDesc = currentClassDesc;
  266. boolean oldBlockDataMode = setBlockData(false);
  267. recursionDepth++;
  268. try {
  269. if (serializeNullAndRepeat(obj, REPLACEABLE))
  270. return;
  271. if (checkSpecialClasses(obj))
  272. return;
  273. Class curclass = obj.getClass();
  274. Class oldclass = null;
  275. Object altobj = obj;
  276. currentClassDesc =
  277. ObjectStreamClass.lookupInternal(curclass);
  278. /* Allow the class to replace the instance to be serialized. */
  279. /* Fix for 4217737: allow replacement object to nominate its own
  280. * replacement, so long as it's not the same class as the replaced
  281. * object.
  282. */
  283. while (currentClassDesc != null &&
  284. currentClassDesc.isReplaceable() &&
  285. curclass != oldclass)
  286. {
  287. altobj = ObjectStreamClass.invokeMethod(
  288. currentClassDesc.writeReplaceMethod,
  289. altobj,
  290. null);
  291. oldclass = curclass;
  292. if (altobj != null) {
  293. curclass = altobj.getClass();
  294. currentClassDesc =
  295. ObjectStreamClass.lookupInternal(curclass);
  296. } else {
  297. curclass = null;
  298. currentClassDesc = null;
  299. }
  300. }
  301. /* If the replacment is enabled, give subclasses one chance
  302. * to substitute a new object. If one is substituted,
  303. * recheck for null, repeated refs, and special cased classes
  304. */
  305. if (enableReplace) {
  306. altobj = replaceObject(altobj);
  307. currentClassDesc = (altobj != null) ?
  308. ObjectStreamClass.lookupInternal(altobj.getClass()) : null;
  309. }
  310. /* If the object has been replaced check that the object
  311. * is serializable and recheck for the special cases.
  312. */
  313. if (obj != altobj) {
  314. if (altobj != null && ! (altobj instanceof Serializable)) {
  315. String clname = altobj.getClass().getName();
  316. throw new NotSerializableException(clname);
  317. }
  318. // If the alternate object is already
  319. // serialized just remember the replacement
  320. if (serializeNullAndRepeat(altobj, REPLACEABLE)) {
  321. addReplacement(obj, altobj);
  322. return;
  323. }
  324. /* Add this to the set of replaced objects.
  325. * This must be done before the object is
  326. * serialized so that if the object indirectly
  327. * refers to the original it will be redirected to
  328. * the replacement.
  329. *
  330. * NB: checkSpecialClasses should only call
  331. * serializeNullandRepeat for objects that will not
  332. * recurse.
  333. */
  334. addReplacement(obj, altobj);
  335. if (checkSpecialClasses(altobj))
  336. return;
  337. obj = altobj;
  338. }
  339. if (checkSubstitutableSpecialClasses(obj,
  340. currentClassDesc.forClass()))
  341. return;
  342. /* Write out the object as itself */
  343. outputObject(obj);
  344. } catch (IOException ee) {
  345. if (abortIOException == null) {
  346. try {
  347. /* Prepare to write the exception to the stream.
  348. * End blockdatamode in case it's set
  349. * Write the exception code
  350. * reset the stream to forget all previous objects
  351. * write the exception that occurred
  352. * reset the stream again so subsequent objects won't map to
  353. * the exception or its args.
  354. * Continue below to rethrow the exception.
  355. */
  356. setBlockData(false);
  357. writeCode(TC_EXCEPTION);
  358. resetStream();
  359. setBlockData(false); //added since resetStream set to TRUE.
  360. currentClassDesc =
  361. ObjectStreamClass.lookupInternal(ee.getClass());
  362. this.outputObject(ee); //avoid recursing with writeObject
  363. resetStream();
  364. // Set the pending exception to be rethrown.
  365. abortIOException = ee;
  366. } catch (IOException fatal) {
  367. /* An exception occurred while writing the original exception to
  368. * the stream. The original exception is not complete in
  369. * the stream and recusion would be bad. Supercede the original
  370. * Exception with a StreamCorruptedException using the message
  371. * from this current exception.
  372. */
  373. abortIOException =
  374. new StreamCorruptedException(fatal.getMessage());
  375. }
  376. }
  377. } finally {
  378. /* Restore state of previous call incase this is a nested call */
  379. recursionDepth--;
  380. currentObject = prevObject;
  381. currentClassDesc = prevClassDesc;
  382. setBlockData(oldBlockDataMode);
  383. }
  384. /* If the recursion depth is 0, test for and clear the pending exception.
  385. * If there is a pending exception throw it.
  386. */
  387. IOException pending = abortIOException;
  388. if (recursionDepth == 0)
  389. abortIOException = null;
  390. if (pending != null) {
  391. throw pending;
  392. }
  393. }
  394. /*
  395. * Check for special cases of serializing objects.
  396. * These objects are not subject to replacement.
  397. */
  398. private boolean checkSpecialClasses(Object obj) throws IOException {
  399. /*
  400. * If this is a class, don't allow substitution
  401. */
  402. if (obj instanceof Class) {
  403. outputClass((Class)obj);
  404. return true;
  405. }
  406. if (obj instanceof ObjectStreamClass) {
  407. outputClassDescriptor((ObjectStreamClass)obj);
  408. return true;
  409. }
  410. return false;
  411. }
  412. /*
  413. * Check for special cases of substitutable serializing objects.
  414. * These classes are replaceable.
  415. */
  416. private boolean checkSubstitutableSpecialClasses(Object obj, Class cl)
  417. throws IOException
  418. {
  419. if (cl == String.class) {
  420. outputString((String)obj);
  421. return true;
  422. }
  423. if (cl.isArray()) {
  424. outputArray(obj);
  425. return true;
  426. }
  427. return false;
  428. }
  429. /**
  430. * Write the non-static and non-transient fields of the current class
  431. * to this stream. This may only be called from the writeObject method
  432. * of the class being serialized. It will throw the NotActiveException
  433. * if it is called otherwise.
  434. *
  435. * @throws IOException if I/O errors occur while writing to the underlying
  436. * <code>OutputStream</code>
  437. */
  438. public void defaultWriteObject() throws IOException {
  439. if (currentObject == null || currentClassDesc == null)
  440. throw new NotActiveException("defaultWriteObject");
  441. ObjectStreamField[] fields =
  442. currentClassDesc.getFieldsNoCopy();
  443. if (fields.length > 0) {
  444. boolean prevmode = setBlockData(false);
  445. outputClassFields(currentObject, currentClassDesc.forClass(),
  446. fields);
  447. setBlockData(prevmode);
  448. }
  449. }
  450. /**
  451. * Retrieve the object used to buffer persistent fields to be written to
  452. * the stream. The fields will be written to the stream when writeFields
  453. * method is called.
  454. *
  455. * @return an instance of the class Putfield that holds the serializable
  456. * fields
  457. * @exception IOException if I/O errors occur
  458. * @since 1.2
  459. */
  460. public ObjectOutputStream.PutField putFields() throws IOException {
  461. if (currentObject == null || currentClassDesc == null)
  462. throw new NotActiveException("putFields");
  463. // TBD: check if defaultWriteObject has already been called.
  464. currentPutFields = new ObjectOutputStream.PutFieldImpl(currentClassDesc);
  465. return currentPutFields;
  466. }
  467. /**
  468. * Write the buffered fields to the stream.
  469. *
  470. * @throws IOException if I/O errors occur while writing to the underlying
  471. * stream
  472. * @throws NotActiveException Called when a classes writeObject
  473. * method was not called to write the state of the object.
  474. * @since 1.2
  475. */
  476. public void writeFields() throws IOException {
  477. if (currentObject == null || currentClassDesc == null || currentPutFields == null)
  478. throw new NotActiveException("writeFields");
  479. boolean prevmode = setBlockData(false);
  480. currentPutFields.write(this);
  481. setBlockData(prevmode);
  482. }
  483. /**
  484. * Reset will disregard the state of any objects already written
  485. * to the stream. The state is reset to be the same as a new
  486. * ObjectOutputStream. The current point in the stream is marked
  487. * as reset so the corresponding ObjectInputStream will be reset
  488. * at the same point. Objects previously written to the stream
  489. * will not be refered to as already being in the stream. They
  490. * will be written to the stream again.
  491. *
  492. * @throws IOException if reset() is invoked while serializing an object.
  493. */
  494. public void reset() throws IOException {
  495. if (currentObject != null || currentClassDesc != null)
  496. throw new IOException("Illegal call to reset");
  497. /* Write a reset to the stream. */
  498. setBlockData(false);
  499. writeCode(TC_RESET);
  500. resetStream(); // re-init the stream
  501. abortIOException = null;
  502. }
  503. /*
  504. * Internal reset function to reinitialize the state of the stream.
  505. * Reset state of things changed by using the stream.
  506. */
  507. private void resetStream() throws IOException {
  508. if (handleTable == null) {
  509. handleTable = new HandleTable(11, (float) 7.0);
  510. } else {
  511. handleTable.clear();
  512. }
  513. if (classDescStack == null) {
  514. classDescStack = new Stack();
  515. } else {
  516. classDescStack.setSize(0);
  517. }
  518. if (replaceTable != null) {
  519. replaceTable.clear();
  520. }
  521. setBlockData(true); /* Re-enable buffering */
  522. }
  523. /**
  524. * Subclasses may implement this method to allow class data to be stored
  525. * in the stream. By default this method does nothing.
  526. * The corresponding method in ObjectInputStream is resolveClass.
  527. * This method is called exactly once for each unique class in the stream.
  528. * The class name and signature will have already been written to the stream.
  529. * This method may make free use of the ObjectOutputStream to save
  530. * any representation of the class it deems suitable (for example,
  531. * the bytes of the class file). The resolveClass method in the corresponding
  532. * subclass of ObjectInputStream must read and use any data or objects
  533. * written by annotateClass.
  534. *
  535. * @param cl the class to annotate custom data for
  536. * @exception IOException Any exception thrown by the underlying OutputStream.
  537. */
  538. protected void annotateClass(Class cl)
  539. throws IOException
  540. {
  541. }
  542. /**
  543. * Subclasses may implement this method to store custom data in the
  544. * stream along with descriptors for dynamic proxy classes.
  545. *
  546. * <p>This method is called exactly once for each unique proxy class
  547. * descriptor in the stream. The default implementation of this
  548. * method in <code>ObjectOutputStream</code> does nothing.
  549. *
  550. * <p>The corresponding method in <code>ObjectInputStream</code> is
  551. * <code>resolveProxyClass</code>. For a given subclass of
  552. * <code>ObjectOutputStream</code> that overrides this method, the
  553. * <code>resolveProxyClass</code> method in the corresponding
  554. * subclass of <code>ObjectInputStream</code> must read any data or
  555. * objects writtem by <code>annotateProxyClass</code>.
  556. *
  557. * @param cl the proxy class to annotate custom data for
  558. * @throws IOException any exception thrown by the underlying
  559. * <code>OutputStream</code>
  560. * @see ObjectInputStream#resolveProxyClass(String[])
  561. * @since 1.3
  562. */
  563. protected void annotateProxyClass(Class cl)
  564. throws IOException
  565. {
  566. }
  567. /**
  568. * This method will allow trusted subclasses of ObjectOutputStream to
  569. * substitute one object for another during serialization. Replacing objects
  570. * is disabled until enableReplaceObject is called. The enableReplaceObject
  571. * method checks that the stream requesting to do replacment can be trusted.
  572. * The first occurrence of each object written into the serialization stream
  573. * is passed to replaceObject. Subsequent references to the object are
  574. * replaced by the object returned by the original call to replaceObject.
  575. * To ensure that the private state of objects is not unintentionally
  576. * exposed, only trusted streams may use replaceObject. <p>
  577. *
  578. * The ObjectOutputStream.writeObject method takes a parameter of type
  579. * Object (as opposed to type Serializable) to allow for cases where
  580. * non-serializable objects are replaced by serializable ones.
  581. *
  582. * When a subclass is replacing objects it must insure that either
  583. * a complementary substitution must be made during
  584. * deserialization or that the substituted object is compatible
  585. * with every field where the reference will be stored. Objects
  586. * whose type is not a subclass of the type of the field or array
  587. * element abort the serialization by raising an exception and the
  588. * object is not be stored. <p>
  589. *
  590. * This method is called only once when each object is first encountered.
  591. * All subsequent references to the object will be redirected to the
  592. * new object. This method should return the object to be substituted or
  593. * the original object. <P>
  594. *
  595. * Null can be returned as the object to be substituted, but may
  596. * cause NullReferenceException in classes that contain references
  597. * to the original object since they may be expecting an object
  598. * instead of null.<p>
  599. *
  600. * @param obj the object to be replaced
  601. * @return the alternate object that replaced the specified one
  602. * @exception IOException Any exception thrown by the underlying
  603. * OutputStream.
  604. */
  605. protected Object replaceObject(Object obj)
  606. throws IOException
  607. {
  608. return obj;
  609. }
  610. /**
  611. * Enable the stream to do replacement of objects in the stream.
  612. *
  613. * <p>When enabled, the replaceObject method is called for every object
  614. * being serialized.
  615. *
  616. * <p>If <i>enable</i> is true, and there is a security manager installed,
  617. * this method first calls the
  618. * security manager's <code>checkPermission</code> method with a
  619. * <code>SerializablePermission("enableSubstitution")</code>
  620. * permission to ensure it's ok to
  621. * enable the stream to do replacement of objects in the stream.
  622. *
  623. * @param enable boolean parameter to enable replacement of objects
  624. * @return the previous setting before this method was invoked
  625. * @throws SecurityException
  626. * if a security manager exists and its
  627. * <code>checkPermission</code> method denies
  628. * enabling the stream to do replacement of objects in the stream.
  629. *
  630. * @see SecurityManager#checkPermission
  631. * @see java.io.SerializablePermission
  632. */
  633. protected boolean enableReplaceObject(boolean enable)
  634. throws SecurityException
  635. {
  636. boolean previous = enableReplace;
  637. if (enable) {
  638. SecurityManager sm = System.getSecurityManager();
  639. if (sm != null) sm.checkPermission(SUBSTITUTION_PERMISSION);
  640. enableReplace = true;
  641. } else {
  642. enableReplace = false;
  643. }
  644. return previous;
  645. }
  646. /**
  647. * The writeStreamHeader method is provided so subclasses can
  648. * append or prepend their own header to the stream.
  649. * It writes the magic number and version to the stream.
  650. *
  651. * @throws IOException if I/O errors occur while writing to the underlying
  652. * stream
  653. */
  654. protected void writeStreamHeader() throws IOException {
  655. writeShort(STREAM_MAGIC);
  656. writeShort(STREAM_VERSION);
  657. }
  658. /**
  659. * Write a string to the stream.
  660. * Note that since Strings are Objects, writeObject
  661. * will behave identically.
  662. */
  663. private void outputString(String s) throws IOException {
  664. long utflen;
  665. int slen = s.length();
  666. handleTable.assignWireOffset(s);
  667. if ((cdata == null) || (cdata.length < slen)) {
  668. cdata = s.toCharArray();
  669. } else {
  670. s.getChars(0, slen, cdata, 0);
  671. }
  672. utflen = getUTFLength(cdata, slen);
  673. if (utflen <= 0xFFFF) { // use normal utf format
  674. writeCode(TC_STRING);
  675. writeShort((int) utflen);
  676. } else { // use long utf format
  677. writeCode(TC_LONGSTRING);
  678. writeLong(utflen);
  679. }
  680. writeUTFBody(cdata, slen);
  681. if (slen > CDATA_MAX_LEN)
  682. cdata = null; // let go of long arrays
  683. }
  684. /**
  685. * Return length of UTF encoding of this string, excluding initial length
  686. * tag.
  687. */
  688. private static long getUTFLength(char[] chars, int len) {
  689. long utflen = 0;
  690. for (int i = 0; i < len; i++) {
  691. int c = chars[i];
  692. if ((c >= 0x0001) && (c <= 0x007F)) {
  693. utflen++;
  694. } else if (c > 0x07FF) {
  695. utflen += 3;
  696. } else {
  697. utflen += 2;
  698. }
  699. }
  700. return utflen;
  701. }
  702. /**
  703. * Write UTF encoding of this string, but don't write initial length tag.
  704. */
  705. private void writeUTFBody(char[] chars, int len)
  706. throws IOException
  707. {
  708. final int PADLEN = 2; // keep extra 2 bytes at end of buffer
  709. int blimit = buf.length - PADLEN;
  710. int c;
  711. for (int i = 0; i < len; i++) {
  712. c = chars[i];
  713. if (count >= blimit) {
  714. if (blockDataMode) {
  715. /* must write utf encoding of character one byte at a time,
  716. * to normalize block data record.
  717. */
  718. if ((c >= 0x0001) && (c <= 0x007F)) {
  719. write(c);
  720. } else if (c > 0x07FF) {
  721. write(0xE0 | ((c >> 12) & 0x0F));
  722. write(0x80 | ((c >> 6) & 0x3F));
  723. write(0x80 | ((c >> 0) & 0x3F));
  724. } else {
  725. write(0xC0 | ((c >> 6) & 0x1F));
  726. write(0x80 | ((c >> 0) & 0x3F));
  727. }
  728. continue;
  729. }
  730. drain();
  731. }
  732. if ((c >= 0x0001) && (c <= 0x007F)) {
  733. buf[count++] = (byte) c;
  734. } else if (c > 0x07FF) {
  735. buf[count++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
  736. buf[count++] = (byte) (0x80 | ((c >> 6) & 0x3F));
  737. buf[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));
  738. } else {
  739. buf[count++] = (byte) (0xC0 | ((c >> 6) & 0x1F));
  740. buf[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));
  741. }
  742. }
  743. }
  744. /* Classes are special, they can not be created during deserialization,
  745. * but the appropriate class can be found.
  746. */
  747. private void outputClass(Class aclass) throws IOException {
  748. writeCode(TC_CLASS);
  749. /* Find the class descriptor and write it out */
  750. ObjectStreamClass v = ObjectStreamClass.lookupInternal(aclass);
  751. if (v == null)
  752. throw new NotSerializableException(aclass.getName());
  753. outputClassDescriptor(v);
  754. handleTable.assignWireOffset(aclass);
  755. }
  756. /**
  757. * Write class descriptor to stream in the default format.
  758. */
  759. private void writeClassDescriptor0(ObjectStreamClass classdesc)
  760. throws IOException
  761. {
  762. writeUTF(classdesc.getName());
  763. writeLong(classdesc.getSerialVersionUID());
  764. classdesc.write(this);
  765. }
  766. /**
  767. * Write the specified class descriptor to the ObjectOutputStream. Class
  768. * descriptors are used to identify the classes of objects written to the
  769. * stream. Subclasses of ObjectOutputStream may override this method to
  770. * customize the way in which class descriptors are written to the
  771. * serialization stream. The corresponding method in ObjectInputStream,
  772. * <code>readClassDescriptor</code>, should then be overridden to
  773. * reconstitute the class descriptor from its custom stream representation.
  774. * By default, this method writes class descriptors according to the format
  775. * defined in the Object Serialization specification.
  776. * <p>
  777. * Note that this method will only be called if the ObjectOutputStream is
  778. * not using the old serialization stream format (set by calling
  779. * ObjectOutputStream's <code>useProtocolVersion</code> method). If this
  780. * serialization stream is using the old format
  781. * (<code>PROTOCOL_VERSION_1</code>), the class descriptor will be written
  782. * internally in a manner that cannot be overridden or customized.
  783. * <p>
  784. *
  785. * @param classdesc class descriptor to write to the stream
  786. * @exception IOException If an I/O error has occurred.
  787. * @see java.io.ObjectInputStream#readClassDescriptor()
  788. * @see #useProtocolVersion(int)
  789. * @see java.io.ObjectStreamConstants#PROTOCOL_VERSION_1
  790. * @since 1.3
  791. */
  792. protected void writeClassDescriptor(ObjectStreamClass classdesc)
  793. throws IOException
  794. {
  795. writeClassDescriptor0(classdesc);
  796. }
  797. /* Write the class descriptor */
  798. private void outputClassDescriptor(ObjectStreamClass classdesc)
  799. throws IOException
  800. {
  801. if (serializeNullAndRepeat(classdesc, NOT_REPLACEABLE))
  802. return;
  803. Class cl = classdesc.forClass();
  804. if (!classdesc.forProxyClass) {
  805. /*
  806. * Write out the type code for a class descriptor.
  807. */
  808. writeCode(TC_CLASSDESC);
  809. /*
  810. * Wire offset must be assigned before class descriptor is
  811. * written, to be symmetric with inputClassDescriptor.
  812. */
  813. handleTable.assignWireOffset(classdesc);
  814. /*
  815. * Write out the class descriptor. If the deprecated
  816. * externalizable format is _not_ being used, give subclasses
  817. * a chance to override class descriptor write hook.
  818. */
  819. if (useDeprecatedExternalizableFormat)
  820. writeClassDescriptor0(classdesc);
  821. else
  822. writeClassDescriptor(classdesc);
  823. /*
  824. * Give subclassers a chance to add the class implementation
  825. * to the stream. Set BlockData mode so any information they
  826. * write can be skipped on reading.
  827. */
  828. boolean prevMode = setBlockData(true);
  829. annotateClass(cl);
  830. setBlockData(prevMode);
  831. writeCode(TC_ENDBLOCKDATA);
  832. /*
  833. * Write out the superclass descriptor of this descriptor
  834. * only if it is for a java.io.Serializable class.
  835. * else write null.
  836. */
  837. ObjectStreamClass superdesc = classdesc.getSuperclass();
  838. outputClassDescriptor(superdesc);
  839. } else {
  840. /*
  841. * Write out the type code for a proxy class descriptor.
  842. */
  843. writeCode(TC_PROXYCLASSDESC);
  844. /*
  845. * The wire handle must be assigned before writing any other
  846. * objects to the stream that could reference this descriptor.
  847. */
  848. handleTable.assignWireOffset(classdesc);
  849. /*
  850. * Write out the names of the proxy interfaces.
  851. */
  852. Class[] interfaces = cl.getInterfaces();
  853. writeInt(interfaces.length);
  854. for (int i = 0; i < interfaces.length; i++) {
  855. writeUTF(interfaces[i].getName());
  856. }
  857. /*
  858. * Give subclasses a change to add custom annotations to the
  859. * proxy class descriptor. Use block data mode to allow
  860. * custom data to be skipped.
  861. */
  862. boolean prevMode = setBlockData(true);
  863. annotateProxyClass(cl);
  864. setBlockData(prevMode);
  865. writeCode(TC_ENDBLOCKDATA);
  866. /*
  867. * Write out the descriptor for the superclass.
  868. */
  869. outputClassDescriptor(classdesc.getSuperclass());
  870. }
  871. }
  872. /**
  873. * Write an array out. Note that since Arrays are Objects, writeObject(obj)
  874. * will behave identically. <br><br>
  875. *
  876. * @param o can represent an array of any type/dimension.
  877. */
  878. private void outputArray(Object obj)
  879. throws IOException
  880. {
  881. Class currclass = currentClassDesc.forClass();
  882. /* Write out the code for an array and the name of the class */
  883. writeCode(TC_ARRAY);
  884. outputClassDescriptor(currentClassDesc);
  885. /* Assign the wirehandle for this object and outputArrayValues
  886. * writes the length and the array contents.
  887. */
  888. handleTable.assignWireOffset(obj);
  889. int i, length, limit;
  890. Class type = currclass.getComponentType();
  891. if (type.isPrimitive()) {
  892. /* Write arrays of primitive types using the DataOutput
  893. * methods that convert each element into the output buffer.
  894. * The data types are ordered by the frequency
  895. * in which they are expected to occur.
  896. *
  897. * Note: there is no need to worry about normalizing block data
  898. * records here, since at this point we're not in block data mode.
  899. */
  900. if (type == Integer.TYPE) {
  901. int[] array = (int[])obj;
  902. length = array.length;
  903. limit = buf.length - 4;
  904. writeInt(length);
  905. for (i = 0; i < length; i++) {
  906. if (count > limit)
  907. drain();
  908. int v = array[i];
  909. buf[count++] = (byte) (v >>> 24);
  910. buf[count++] = (byte) (v >>> 16);
  911. buf[count++] = (byte) (v >>> 8);
  912. buf[count++] = (byte) (v >>> 0);
  913. }
  914. } else if (type == Byte.TYPE) {
  915. byte[] array = (byte[])obj;
  916. length = array.length;
  917. writeInt(length);
  918. writeInternal(array, 0, length, true);
  919. } else if (type == Long.TYPE) {
  920. long[] array = (long[])obj;
  921. length = array.length;
  922. limit = buf.length - 8;
  923. writeInt(length);
  924. for (i = 0; i < length; i++) {
  925. if (count > limit)
  926. drain();
  927. long v = array[i];
  928. buf[count++] = (byte) (v >>> 56);
  929. buf[count++] = (byte) (v >>> 48);
  930. buf[count++] = (byte) (v >>> 40);
  931. buf[count++] = (byte) (v >>> 32);
  932. buf[count++] = (byte) (v >>> 24);
  933. buf[count++] = (byte) (v >>> 16);
  934. buf[count++] = (byte) (v >>> 8);
  935. buf[count++] = (byte) (v >>> 0);
  936. }
  937. } else if (type == Float.TYPE) {
  938. float[] array = (float[])obj;
  939. length = array.length;
  940. writeInt(length);
  941. int off = 0;
  942. while (length > 0) {
  943. int avail = (buf.length - count) >> 2;
  944. if (avail > 0) {
  945. int n = (length < avail) ? length : avail;
  946. floatsToBytes(array, off, buf, count, n);
  947. off += n;
  948. length -= n;
  949. count += n << 2;
  950. } else {
  951. drain();
  952. }
  953. }
  954. } else if (type == Double.TYPE) {
  955. double[] array = (double[])obj;
  956. length = array.length;
  957. writeInt(length);
  958. int off = 0;
  959. while (length > 0) {
  960. int avail = (buf.length - count) >> 3;
  961. if (avail > 0) {
  962. int n = (length < avail) ? length : avail;
  963. doublesToBytes(array, off, buf, count, n);
  964. off += n;
  965. length -= n;
  966. count += n << 3;
  967. } else {
  968. drain();
  969. }
  970. }
  971. } else if (type == Short.TYPE) {
  972. short[] array = (short[])obj;
  973. length = array.length;
  974. limit = buf.length - 2;
  975. writeInt(length);
  976. for (i = 0; i < length; i++) {
  977. if (count > limit)
  978. drain();
  979. short v = array[i];
  980. buf[count++] = (byte) (v >>> 8);
  981. buf[count++] = (byte) (v >>> 0);
  982. }
  983. } else if (type == Character.TYPE) {
  984. char[] array = (char[])obj;
  985. length = array.length;
  986. limit = buf.length - 2;
  987. writeInt(length);
  988. for (i = 0; i < length; i++) {
  989. if (count > limit)
  990. drain();
  991. char v = array[i];
  992. buf[count++] = (byte) (v >>> 8);
  993. buf[count++] = (byte) (v >>> 0);
  994. }
  995. } else if (type == Boolean.TYPE) {
  996. boolean[] array = (boolean[])obj;
  997. length = array.length;
  998. limit = buf.length - 1;
  999. writeInt(length);
  1000. for (i = 0; i < length; i++) {
  1001. if (count > limit)
  1002. drain();
  1003. buf[count++] = (byte) (array[i] ? 1 : 0);
  1004. }
  1005. } else {
  1006. throw new InvalidClassException(currclass.getName());
  1007. }
  1008. } else {
  1009. Object[] array = (Object[])obj;
  1010. length = array.length;
  1011. writeInt(length);
  1012. for (i = 0; i < length; i++) {
  1013. writeObject(array[i]);
  1014. }
  1015. }
  1016. }
  1017. /*
  1018. * Convert nfloats float values to their byte representations. Float values
  1019. * are read from array src starting at offset srcpos and written to array
  1020. * dst starting at offset dstpos.
  1021. */
  1022. private static native void floatsToBytes(float[] src, int srcpos,
  1023. byte[] dst, int dstpos, int nfloats);
  1024. /*
  1025. * Convert ndoubles double values to their byte representations. Double
  1026. * values are read from array src starting at offset srcpos and written to
  1027. * array dst starting at offset dstpos.
  1028. */
  1029. private static native void doublesToBytes(double[] src, int srcpos,
  1030. byte[] dst, int dstpos, int ndoubles);
  1031. /*
  1032. * Write a typeString to the stream.
  1033. * Do not allow replaceObject to be called on typeString.
  1034. */
  1035. void writeTypeString(String typeString) throws IOException {
  1036. int handle = handleTable.findWireOffset(typeString);
  1037. if (handle >= 0) {
  1038. writeCode(TC_REFERENCE);
  1039. writeInt(handle + baseWireHandle);
  1040. } else {
  1041. handleTable.assignWireOffset(typeString);
  1042. writeCode(TC_STRING);
  1043. writeUTF(typeString);
  1044. }
  1045. }
  1046. /*
  1047. * Put the object into the stream The newObject code is written
  1048. * followed by the ObjectStreamClass for the object's class. Each
  1049. * of the objects classes is written using the default
  1050. * serialization code and dispatching to Specials where
  1051. * appropriate.
  1052. */
  1053. private void outputObject(Object obj)
  1054. throws IOException
  1055. {
  1056. currentObject = obj;
  1057. if (currentClassDesc.isNonSerializable()) {
  1058. throw new NotSerializableException(currentClassDesc.getName());
  1059. }
  1060. /* Write the code to expect an instance and
  1061. * the class descriptor of the instance
  1062. */
  1063. writeCode(TC_OBJECT);
  1064. outputClassDescriptor(currentClassDesc);
  1065. /* Assign the next wirehandle */
  1066. handleTable.assignWireOffset(obj);
  1067. /* If the object is externalizable,
  1068. * call writeExternal.
  1069. * else do Serializable processing.
  1070. */
  1071. if (currentClassDesc.isExternalizable()) {
  1072. Externalizable ext = (Externalizable)obj;
  1073. if (useDeprecatedExternalizableFormat) {
  1074. /* JDK 1.1 external data format.
  1075. * Don't write in block data mode and no terminator tag.
  1076. */
  1077. ext.writeExternal(this);
  1078. } else {
  1079. /* Java 2 SDK Externalizable data format writes in block data mode
  1080. * and terminates externalizable data with TAG_ENDBLOCKDATA.
  1081. */
  1082. setBlockData(true);
  1083. try {
  1084. ext.writeExternal(this);
  1085. } finally {
  1086. setBlockData(false);
  1087. writeCode(TC_ENDBLOCKDATA);
  1088. }
  1089. }
  1090. } else {
  1091. /* The object's classes should be processed from supertype to subtype
  1092. * Push all the clases of the current object onto a stack.
  1093. * Remember the stack pointer where this set of classes is being pushed.
  1094. */
  1095. int stackMark = classDescStack.size();
  1096. try {
  1097. ObjectStreamClass next;
  1098. while ((next = currentClassDesc.getSuperclass()) != null) {
  1099. classDescStack.push(currentClassDesc);
  1100. currentClassDesc = next;
  1101. }
  1102. /*
  1103. * For currentClassDesc and all the pushed class descriptors
  1104. * If the class is writing its own data
  1105. * set blockData = true; call the class writeObject method
  1106. * If not
  1107. * invoke either the defaultWriteObject method.
  1108. */
  1109. do {
  1110. if (currentClassDesc.hasWriteObject()) {
  1111. setBlockData(true); /* Block any data the class writes */
  1112. invokeObjectWriter(obj);
  1113. setBlockData(false);
  1114. writeCode(TC_ENDBLOCKDATA);
  1115. } else {
  1116. defaultWriteObject();
  1117. }
  1118. } while (classDescStack.size() > stackMark &&
  1119. (currentClassDesc = (ObjectStreamClass)classDescStack.pop()) != null);
  1120. } finally {
  1121. classDescStack.setSize(stackMark);
  1122. }
  1123. }
  1124. }
  1125. /*
  1126. * Return a replacement for 'forObject', if one exists.
  1127. */
  1128. private Object lookupReplace(Object obj) {
  1129. return (replaceTable != null) ? replaceTable.lookup(obj) : obj;
  1130. }
  1131. /* Serialize the reference if it is NULL or is for an object that
  1132. * was already replaced or already serialized.
  1133. * If the object was already replaced, look for the replacement
  1134. * object in the known objects and if found, write its handle
  1135. *
  1136. * @param checkForReplace only if true. Enables optimization of
  1137. * not checking for replacement of non-replacable
  1138. * objects.
  1139. * @return True if the reference is either null or a repeat.
  1140. */
  1141. private boolean serializeNullAndRepeat(Object obj, boolean checkForReplace)
  1142. throws IOException
  1143. {
  1144. if (obj == null) {
  1145. writeCode(TC_NULL);
  1146. return true;
  1147. }
  1148. /* Look to see if this object has already been replaced.
  1149. * If so, proceed using the replacement object.
  1150. */
  1151. if (checkForReplace) {
  1152. obj = lookupReplace(obj);
  1153. }
  1154. int handle = handleTable.findWireOffset(obj);
  1155. if (handle >= 0) {
  1156. /* Add a reference to the stream */
  1157. writeCode(TC_REFERENCE);
  1158. writeInt(handle + baseWireHandle);
  1159. return true;
  1160. }
  1161. return false; // not serialized, its up to the caller
  1162. }
  1163. /*
  1164. * Add a replacement object to the table.
  1165. * The even numbered indices are the original objects.
  1166. * The odd numbered indices are the replacement objects.
  1167. *
  1168. */
  1169. private void addReplacement(Object orig, Object replacement) {
  1170. if (replaceTable == null) {
  1171. replaceTable = new ReplaceTable(11, (float) 7.0);
  1172. }
  1173. replaceTable.assign(orig, replacement);
  1174. }
  1175. /* Write out the code indicating the type what follows.
  1176. * See ObjectStreamConstants for definitions.
  1177. */
  1178. private void writeCode(int tag)
  1179. throws IOException
  1180. {
  1181. writeByte(tag);
  1182. }
  1183. /*
  1184. * Implement the OutputStream methods. The stream has
  1185. * two modes used internally to ObjectOutputStream. When
  1186. * in BlockData mode, all writes are buffered and written
  1187. * to the underlying stream prefixed by a code and length.
  1188. * When not in BlockData mode (false), writes pass directly
  1189. * through to the underlying stream.
  1190. * The BlockData mode is used to encapsulate data written
  1191. * by class specific writeObject methods that is intended
  1192. * only to be read by corresponding readObject method of the
  1193. * same class. The blocking of data allows it to be skipped
  1194. * if necessary.
  1195. *
  1196. * The setBlockData method is used to switch buffering
  1197. * on and off. When switching between on and off
  1198. * the buffer is drained.
  1199. *
  1200. * The actual buffering is very similar to that of
  1201. * BufferedOutputStream but BufferedOutputStream can
  1202. * write to the underlying stream without the headers.
  1203. */
  1204. private boolean blockDataMode; /* true to buffer and block data */
  1205. private byte[] buf; /* byte array of buffered data. */
  1206. private int count; /* count of bytes in the buffer */
  1207. private OutputStream out; /* Stream to write the data to */
  1208. /**
  1209. * Writes a byte. This method will block until the byte is actually
  1210. * written.
  1211. *
  1212. * @param data the byte to be written to the stream
  1213. * @exception IOException If an I/O error has occurred.
  1214. */
  1215. public void write(int data) throws IOException {
  1216. if (count >= buf.length)
  1217. drain(); /* Drain, make room for more */
  1218. buf[count++] = (byte)data;
  1219. }
  1220. /**
  1221. * Writes an array of bytes. This method will block until the bytes
  1222. * are actually written.
  1223. *
  1224. * @param b the data to be written
  1225. * @exception IOException If an I/O error has occurred.
  1226. */
  1227. public void write(byte b[]) throws IOException {
  1228. write(b, 0, b.length);
  1229. }
  1230. /*
  1231. * Writes a sub array of bytes.
  1232. *
  1233. * @param b the data to be written
  1234. * @param off the start offset in the data
  1235. * @param len the number of bytes that are written
  1236. * @param copyOnWrite do not expose b to overrides of ObjectStream.write,
  1237. * copy the contents of b to a buffer before writing.
  1238. * @exception IOException If an I/O error has occurred.
  1239. */
  1240. private void writeInternal(byte b[], int off, int len,
  1241. boolean copyOnWrite) throws IOException {
  1242. if ((len < 0) || (off < 0) || (off + len > b.length)) {
  1243. throw new IndexOutOfBoundsException();
  1244. }
  1245. if (len == 0) {
  1246. return;
  1247. }
  1248. if (blockDataMode) {
  1249. writeCanonical(b, off, len);
  1250. } else {
  1251. /*
  1252. * If array will fit in output buffer, copy it in there; otherwise,
  1253. * drain anything in the buffer and send it through to underlying
  1254. * output stream directly.
  1255. */
  1256. int avail = buf.length - count;
  1257. if (len <= avail) {
  1258. System.arraycopy(b, off, buf, count, len);
  1259. count += len;
  1260. } else if (copyOnWrite) {
  1261. bufferedWrite(b, off, len);
  1262. } else {
  1263. drain();
  1264. out.write(b, off, len);
  1265. }
  1266. }
  1267. }
  1268. /**
  1269. * Writes a sub array of bytes.
  1270. *
  1271. * @param b the data to be written
  1272. * @param off the start offset in the data
  1273. * @param len the number of bytes that are written
  1274. * @exception IOException If an I/O error has occurred.
  1275. */
  1276. public void write(byte b[], int off, int len) throws IOException {
  1277. writeInternal(b, off, len, false);
  1278. }
  1279. /* Use write buffering of byte[] b to prevent exposure of
  1280. * 'b' reference to untrusted overrides of ObjectOutput.write(byte[]).
  1281. *
  1282. * NOTE: Method is only intended for protecting serializable byte []
  1283. * fields written by default serialization. Thus, it can
  1284. * never get called while in blockDataMode.
  1285. */
  1286. private void bufferedWrite(byte b[], int off, int len) throws IOException {
  1287. int bufAvail = buf.length - count;
  1288. int bytesToWrite = len;
  1289. // Handle case where byte array is larger than available buffer.
  1290. if (bytesToWrite > bufAvail) {
  1291. // Logically: fill rest of 'buf' with 'b' and drain.
  1292. System.arraycopy(b, off, buf, count, bufAvail);
  1293. off += bufAvail;
  1294. bytesToWrite -= bufAvail;
  1295. out.write(buf, 0, buf.length);
  1296. count = 0;
  1297. // Write out buf.length chunks of byte array.
  1298. while (bytesToWrite >= buf.length) {
  1299. System.arraycopy(b, off, buf, 0, buf.length);
  1300. out.write(buf, 0, buf.length);
  1301. off += buf.length;
  1302. bytesToWrite -= buf.length;
  1303. // Optimization: do not modify or access "count" in this loop.
  1304. }
  1305. }
  1306. // Put remainder of byte array b into buffer.
  1307. if (bytesToWrite != 0) {
  1308. System.arraycopy(b, off, buf, count, bytesToWrite);
  1309. count += bytesToWrite;
  1310. }
  1311. }
  1312. /**
  1313. * Flushes the stream. This will write any buffered
  1314. * output bytes and flush through to the underlying stream.
  1315. *
  1316. * @exception IOException If an I/O error has occurred.
  1317. */
  1318. public void flush() throws IOException {
  1319. drain();
  1320. out.flush();
  1321. }
  1322. /**
  1323. * Drain any buffered data in ObjectOutputStream. Similar to flush
  1324. * but does not propagate the flush to the underlaying stream.
  1325. *
  1326. * @throws IOException if I/O errors occur while writing to the underlying
  1327. * stream
  1328. */
  1329. protected void drain() throws IOException {
  1330. /*
  1331. * Drain the data buffer.
  1332. * If the blocking mode is on, prepend the buffer
  1333. * with the code for a blocked data and the length.
  1334. * The code is TC_BLOCKDATA and the length is < 255 so it fits
  1335. * in a byte.
  1336. */
  1337. if (count == 0)
  1338. return;
  1339. if (blockDataMode)
  1340. writeBlockDataHeader(count);
  1341. out.write(buf, 0, count);
  1342. count = 0;
  1343. }
  1344. /**
  1345. * Closes the stream. This method must be called
  1346. * to release any resources associated with the
  1347. * stream.
  1348. *
  1349. * @exception IOException If an I/O error has occurred.
  1350. */
  1351. public void close() throws IOException {
  1352. flush(); /* Make sure we're not holding any data */
  1353. out.close();
  1354. }
  1355. /*
  1356. * Set the blockData mode, if it turned from on to off
  1357. * the buffer is drained. The previous mode is returned.
  1358. */
  1359. private boolean setBlockData(boolean mode) throws IOException {
  1360. if (blockDataMode == mode)
  1361. return mode;
  1362. drain();
  1363. blockDataMode = mode;
  1364. return !mode; /* previous value was the opposite */
  1365. }
  1366. /* Write the Block-data marker and the length of the data to follow
  1367. * to stream 'out'. If the length is < 256, use the short header form.
  1368. * othewise use the long form.
  1369. */
  1370. private void writeBlockDataHeader(int len) throws IOException {
  1371. if (len <= 255) {
  1372. out.write(TC_BLOCKDATA);
  1373. out.write((byte)len);
  1374. } else {
  1375. // use block data with int size if necessary
  1376. out.write(TC_BLOCKDATALONG);
  1377. // send 32 bit int directly to underlying stream
  1378. out.write((byte)((len >> 24) & 0xFF));
  1379. out.write((byte)((len >> 16) & 0xFF));
  1380. out.write((byte)((len >> 8) & 0xFF));
  1381. out.write((byte)(len & 0xFF));
  1382. }
  1383. }
  1384. /* Canonical form requires constant blocking factor. Write data
  1385. * in b array in constant block-data chunks.
  1386. *
  1387. * Assumes only called when blockDataMode is true.
  1388. */
  1389. private void writeCanonical(byte b[], int off, int len)
  1390. throws IOException
  1391. {
  1392. int bufAvail = buf.length - count;
  1393. int bytesToWrite = len;
  1394. // Handle case where byte array is larger than available buffer.
  1395. if (bytesToWrite > bufAvail) {
  1396. // Logically: fill rest of 'buf' with 'b' and drain.
  1397. // Optimization: avoid copying to 'buf', write partial 'buf' and partial
  1398. // 'b' directly to 'out'.
  1399. writeBlockDataHeader(buf.length);
  1400. out.write(buf, 0, count);
  1401. out.write(b, off, bufAvail);
  1402. count = 0;
  1403. off += bufAvail;
  1404. bytesToWrite -= bufAvail;
  1405. // Optimization: write 'buf.length' BlockData directly to stream.
  1406. while (bytesToWrite >= buf.length) {
  1407. if (blockDataMode)
  1408. writeBlockDataHeader(buf.length);
  1409. out.write(b, off, buf.length);
  1410. off += buf.length;
  1411. bytesToWrite -= buf.length;
  1412. }
  1413. }
  1414. // Put remainder of byte array into buffer.
  1415. if (bytesToWrite != 0) {
  1416. System.arraycopy(b, off, buf, count, bytesToWrite);
  1417. count += bytesToWrite;
  1418. }
  1419. }
  1420. /* -------------------------------------------------------------- */
  1421. /*
  1422. * Provide the methods to implement DataOutput. When possible, values are
  1423. * written directly to the internal buffer.
  1424. *
  1425. * Note that each block data record must be filled to capacity (1024 bytes),
  1426. * unless block data mode terminates before 1024 bytes has been reached.
  1427. * This "canonical" block data size allows serialized objects to be compared
  1428. * against each other by checking whether or not the bytes of their
  1429. * serialized representations differ.
  1430. *
  1431. * Consequently, if the current block data record is near capacity and only
  1432. * has f bytes free, and we're attempting to write a primitive value p of
  1433. * length l where l > f, then we must write the first f bytes of p in the
  1434. * current data block, and the l - f remaining bytes in the next data block.
  1435. * The easiest way to do this is to delegate to DataOutputStream, which will
  1436. * write the values one byte at a time through
  1437. * ObjectOutputStream.write(int), ensuring that the data block is completely
  1438. * filled before draining it.
  1439. */
  1440. private DataOutputStream dos;
  1441. /**
  1442. * Writes a boolean.
  1443. *
  1444. * @param data the boolean to be written
  1445. * @throws IOException if I/O errors occur while writing to the underlying
  1446. * stream
  1447. */
  1448. public void writeBoolean(boolean data) throws IOException {
  1449. if (count >= buf.length) {
  1450. dos.writeBoolean(data);
  1451. return;
  1452. }
  1453. buf[count++] = (byte) (data ? 1 : 0);
  1454. }
  1455. /**
  1456. * Writes an 8 bit byte.
  1457. *
  1458. * @param data the byte value to be written
  1459. * @throws IOException if I/O errors occur while writing to the underlying
  1460. * stream
  1461. */
  1462. public void writeByte(int data) throws IOException {
  1463. if (count >= buf.length) {
  1464. dos.writeByte(data);
  1465. return;
  1466. }
  1467. buf[count++] = (byte) data;
  1468. }
  1469. /**
  1470. * Writes a 16 bit short.
  1471. *
  1472. * @param data the short value to be written
  1473. * @throws IOException if I/O errors occur while writing to the underlying
  1474. * stream
  1475. */
  1476. public void writeShort(int data) throws IOException {
  1477. if (count + 2 > buf.length) { // canonicalize data block
  1478. dos.writeShort(data);
  1479. return;
  1480. }
  1481. buf[count++] = (byte) (data >>> 8);
  1482. buf[count++] = (byte) (data >>> 0);
  1483. }
  1484. /**
  1485. * Writes a 16 bit char.
  1486. *
  1487. * @param data the char value to be written
  1488. * @throws IOException if I/O errors occur while writing to the underlying
  1489. * stream
  1490. */
  1491. public void writeChar(int data) throws IOException {
  1492. if (count + 2 > buf.length) { // canonicalize data block
  1493. dos.writeChar(data);
  1494. return;
  1495. }
  1496. buf[count++] = (byte) (data >>> 8);
  1497. buf[count++] = (byte) (data >>> 0);
  1498. }
  1499. /**
  1500. * Writes a 32 bit int.
  1501. *
  1502. * @param data the integer value to be written
  1503. * @throws IOException if I/O errors occur while writing to the underlying
  1504. * stream
  1505. */
  1506. public void writeInt(int data) throws IOException {
  1507. if (count + 4 > buf.length) { // canonicalize data block
  1508. dos.writeInt(data);
  1509. return;
  1510. }
  1511. buf[count++] = (byte) (data >>> 24);
  1512. buf[count++] = (byte) (data >>> 16);
  1513. buf[count++] = (byte) (data >>> 8);
  1514. buf[count++] = (byte) (data >>> 0);
  1515. }
  1516. /**
  1517. * Writes a 64 bit long.
  1518. *
  1519. * @param data the long value to be written
  1520. * @throws IOException if I/O errors occur while writing to the underlying
  1521. * stream
  1522. */
  1523. public void writeLong(long data) throws IOException {
  1524. if (count + 8 > buf.length) { // canonicalize data block
  1525. dos.writeLong(data);
  1526. return;
  1527. }
  1528. buf[count++] = (byte) (data >>> 56);
  1529. buf[count++] = (byte) (data >>> 48);
  1530. buf[count++] = (byte) (data >>> 40);
  1531. buf[count++] = (byte) (data >>> 32);
  1532. buf[count++] = (byte) (data >>> 24);
  1533. buf[count++] = (byte) (data >>> 16);
  1534. buf[count++] = (byte) (data >>> 8);
  1535. buf[count++] = (byte) (data >>> 0);
  1536. }
  1537. /**
  1538. * Writes a 32 bit float.
  1539. *
  1540. * @param data the float value to be written
  1541. * @throws IOException if I/O errors occur while writing to the underlying
  1542. * stream
  1543. */
  1544. public void writeFloat(float data) throws IOException {
  1545. int value = Float.floatToIntBits(data);
  1546. if (count + 4 > buf.length) { // canonicalize data block
  1547. dos.writeFloat(data);
  1548. return;
  1549. }
  1550. buf[count++] = (byte) (value >>> 24);
  1551. buf[count++] = (byte) (value >>> 16);
  1552. buf[count++] = (byte) (value >>> 8);
  1553. buf[count++] = (byte) (value >>> 0);
  1554. }
  1555. /**
  1556. * Writes a 64 bit double.
  1557. *
  1558. * @param data the double value to be written
  1559. * @throws IOException if I/O errors occur while writing to the underlying
  1560. * stream
  1561. */
  1562. public void writeDouble(double data) throws IOException {
  1563. long value = Double.doubleToLongBits(data);
  1564. if (count + 8 > buf.length) { // canonicalize data block
  1565. dos.writeDouble(data);
  1566. return;
  1567. }
  1568. buf[count++] = (byte) (value >>> 56);
  1569. buf[count++] = (byte) (value >>> 48);
  1570. buf[count++] = (byte) (value >>> 40);
  1571. buf[count++] = (byte) (value >>> 32);
  1572. buf[count++] = (byte) (value >>> 24);
  1573. buf[count++] = (byte) (value >>> 16);
  1574. buf[count++] = (byte) (value >>> 8);
  1575. buf[count++] = (byte) (value >>> 0);
  1576. }
  1577. /**
  1578. * Writes a String as a sequence of bytes.
  1579. *
  1580. * @param data the String of bytes to be written
  1581. * @throws IOException if I/O errors occur while writing to the underlying
  1582. * stream
  1583. */
  1584. public void writeBytes(String data) throws IOException {
  1585. char[] chars = data.toCharArray();
  1586. int len = chars.length;
  1587. int buflen = buf.length;
  1588. for (int i = 0; i < len; i++) {
  1589. if (count >= buflen)
  1590. drain();
  1591. buf[count++] = (byte) chars[i];
  1592. }
  1593. }
  1594. /**
  1595. * Writes a String as a sequence of chars.
  1596. *
  1597. * @param data the String of chars to be written
  1598. * @throws IOException if I/O errors occur while writing to the underlying
  1599. * stream
  1600. */
  1601. public void writeChars(String data) throws IOException {
  1602. char[] chars = data.toCharArray();
  1603. int len = chars.length;
  1604. int limit = buf.length - 2;
  1605. char c;
  1606. for (int i = 0; i < len; i++) {
  1607. c = chars[i];
  1608. if (count > limit) {
  1609. dos.writeChar(c);
  1610. } else {
  1611. buf[count++] = (byte) (c >>> 8);
  1612. buf[count++] = (byte) (c >>> 0);
  1613. }
  1614. }
  1615. }
  1616. /**
  1617. * Primitive data write of this String in UTF format.
  1618. *
  1619. * Note that there is a significant difference between
  1620. * writing a String into the stream as primitive data or
  1621. * as an Object. A String instance written by writeObject
  1622. * is written into the stream as a String initially. Future
  1623. * writeObject() calls write references to the string into
  1624. * the stream.
  1625. *
  1626. * @param s the String in UTF format
  1627. * @throws IOException if I/O errors occur while writing to the underlying
  1628. * stream
  1629. */
  1630. public void writeUTF(String s) throws IOException {
  1631. long utflen;
  1632. int slen = s.length();
  1633. if ((cdata == null) || (cdata.length < slen)) {
  1634. cdata = s.toCharArray();
  1635. } else {
  1636. s.getChars(0, slen, cdata, 0);
  1637. }
  1638. utflen = getUTFLength(cdata, slen);
  1639. if (utflen > 0xFFFF)
  1640. throw new UTFDataFormatException();
  1641. writeShort((int) utflen);
  1642. writeUTFBody(cdata, slen);
  1643. if (slen > CDATA_MAX_LEN)
  1644. cdata = null; // let go of long arrays
  1645. }
  1646. /* Write the fields of the specified class by invoking the appropriate
  1647. * write* method on this class.
  1648. */
  1649. private void outputClassFields(Object o, Class cl,
  1650. ObjectStreamField[] fields)
  1651. throws IOException, InvalidClassException
  1652. {
  1653. /*
  1654. * Fetch and write primitive data fields to the output stream.
  1655. */
  1656. int numPrimBytes = currentClassDesc.numPrimBytes;
  1657. if (numPrimBytes > 0) {
  1658. if (data == null) {
  1659. data = new byte[Math.max(numPrimBytes, INITIAL_BUFFER_SIZE)];
  1660. } else if (data.length < numPrimBytes) {
  1661. data = new byte[numPrimBytes];
  1662. }
  1663. getPrimitiveFieldValues(o, currentClassDesc.primFieldIDs,
  1664. currentClassDesc.primFieldTypecodes, data);
  1665. writeInternal(data, 0, numPrimBytes, false);
  1666. }
  1667. int numPrimFields = fields.length - currentClassDesc.numObjFields;
  1668. long[] objFieldIDs = currentClassDesc.objFieldIDs;
  1669. for (int i = 0; i < currentClassDesc.numObjFields; i++) {
  1670. Object val;
  1671. try {
  1672. val = getObjectFieldValue(o, objFieldIDs[i]);
  1673. } catch (Exception e) {
  1674. throw new InvalidClassException(cl.getName(),
  1675. "Invalid field " + fields[numPrimFields + i].getName());
  1676. }
  1677. writeObject(val);
  1678. }
  1679. }
  1680. /*
  1681. * Gets the values of the primitive fields of object obj. fieldIDs is an
  1682. * array of field IDs (the primFieldsID field of the appropriate
  1683. * ObjectStreamClass) identifying which fields to get. typecodes is an
  1684. * array of characters designating the primitive type of each field (e.g.,
  1685. * 'C' for char, 'Z' for boolean, etc.) data is the byte buffer in which
  1686. * the primitive field values are written, in the order of their field IDs.
  1687. *
  1688. * For efficiency, this method does not check all of its arguments for
  1689. * safety. Specifically, it assumes that obj's type is compatible with the
  1690. * given field IDs, and that the data array is long enough to contain all of
  1691. * the byte values that will be written to it.
  1692. */
  1693. private static native void getPrimitiveFieldValues(Object obj,
  1694. long[] fieldIDs, char[] typecodes, byte[] data);
  1695. /*
  1696. * Gets the value of an object field of object obj. fieldID is the field ID
  1697. * identifying which field to set (obtained from the objFieldsID array field
  1698. * of the appropriate ObjectStreamClass).
  1699. *
  1700. * For efficiency, this method does not check to make sure that obj's type
  1701. * is compatible with the given field ID.
  1702. */
  1703. private static native Object getObjectFieldValue(Object obj, long fieldID);
  1704. /*
  1705. * Test if WriteObject method is present, and if so, invoke writer.
  1706. */
  1707. private void invokeObjectWriter(Object obj)
  1708. throws IOException
  1709. {
  1710. try {
  1711. currentClassDesc.writeObjectMethod.invoke(obj, writeObjectArglist);
  1712. } catch (InvocationTargetException e) {
  1713. Throwable t = e.getTargetException();
  1714. if (t instanceof IOException)
  1715. throw (IOException)t;
  1716. else if (t instanceof RuntimeException)
  1717. throw (RuntimeException) t;
  1718. else if (t instanceof Error)
  1719. throw (Error) t;
  1720. else
  1721. throw new Error("internal error");
  1722. } catch (IllegalAccessException e) {
  1723. /* Should not happen, unless there is a problem with the VM. This
  1724. * is because the writeObject method is obtained via
  1725. * ObjectStreamClass.getDeclaredMethod, which calls setAccessible
  1726. * on it, in privileged mode.
  1727. */
  1728. throw new InternalError("Unable to access writeObject method");
  1729. }
  1730. }
  1731. /*************************************/
  1732. /**
  1733. * Provide programatic access to the persistent fields to be written
  1734. * to ObjectOutput.
  1735. *
  1736. * @since 1.2
  1737. */
  1738. static public abstract class PutField {
  1739. /**
  1740. * Put the value of the named boolean field into the persistent field.
  1741. *
  1742. * @param name the name of the serializable field
  1743. * @param value the value to assign to the field
  1744. */
  1745. abstract public void put(String name, boolean value);
  1746. /**
  1747. * Put the value of the named char field into the persistent fields.
  1748. *
  1749. * @param name the name of the serializable field
  1750. * @param value the value to assign to the field
  1751. */
  1752. abstract public void put(String name, char value);
  1753. /**
  1754. * Put the value of the named byte field into the persistent fields.
  1755. *
  1756. * @param name the name of the serializable field
  1757. * @param value the value to assign to the field
  1758. */
  1759. abstract public void put(String name, byte value);
  1760. /**
  1761. * Put the value of the named short field into the persistent fields.
  1762. *
  1763. * @param name the name of the serializable field
  1764. * @param value the value to assign to the field
  1765. */
  1766. abstract public void put(String name, short value);
  1767. /**
  1768. * Put the value of the named int field into the persistent fields.
  1769. *
  1770. * @param name the name of the serializable field
  1771. * @param value the value to assign to the field
  1772. */
  1773. abstract public void put(String name, int value);
  1774. /**
  1775. * Put the value of the named long field into the persistent fields.
  1776. *
  1777. * @param name the name of the serializable field
  1778. * @param value the value to assign to the field
  1779. */
  1780. abstract public void put(String name, long value);
  1781. /**
  1782. * Put the value of the named float field into the persistent fields.
  1783. *
  1784. * @param name the name of the serializable field
  1785. * @param value the value to assign to the field
  1786. */
  1787. abstract public void put(String name, float value);
  1788. /**
  1789. * Put the value of the named double field into the persistent field.
  1790. *
  1791. * @param name the name of the serializable field
  1792. * @param value the value to assign to the field
  1793. */
  1794. abstract public void put(String name, double value);
  1795. /**
  1796. * Put the value of the named Object field into the persistent field.
  1797. *
  1798. * @param name the name of the serializable field
  1799. * @param value the value to assign to the field
  1800. */
  1801. abstract public void put(String name, Object value);
  1802. /**
  1803. * Write the data and fields to the specified ObjectOutput stream.
  1804. *
  1805. * @param out the stream to write the data and fields to
  1806. * @throws IOException if I/O errors occur while writing to the
  1807. * underlying stream
  1808. */
  1809. abstract public void write(ObjectOutput out) throws IOException;
  1810. };
  1811. /*************************************************************/
  1812. /**
  1813. * Provide access to the persistent fields to be written to the output
  1814. * stream.
  1815. */
  1816. static final class PutFieldImpl extends PutField {
  1817. /**
  1818. * Put the value of the named boolean field into the persistent field.
  1819. *
  1820. * @param name the name of the serializable field
  1821. * @param value the value to assign to the field
  1822. * @throws IllegalArgumentException if specified field does not exist
  1823. * or the type of the field does not match the type of
  1824. * <code>value</code>
  1825. */
  1826. public void put(String name, boolean value)
  1827. throws IllegalArgumentException
  1828. {
  1829. ObjectStreamField field = desc.getField(name, Boolean.TYPE);
  1830. if (field == null || field.getType() != Boolean.TYPE)
  1831. throw new IllegalArgumentException("No such boolean field");
  1832. data[field.getOffset()] = (byte)(value ? 1 : 0);
  1833. }
  1834. /**
  1835. * Put the value of the named char field into the persistent fields.
  1836. *
  1837. * @param name the name of the serializable field
  1838. * @param value the value to assign to the field
  1839. * @throws IllegalArgumentException if specified field does not exist
  1840. * or the type of the field does not match the type of
  1841. * <code>value</code>
  1842. */
  1843. public void put(String name, char value) {
  1844. ObjectStreamField field = desc.getField(name, Character.TYPE);
  1845. if (field == null || field.getType() != Character.TYPE)
  1846. throw new IllegalArgumentException("No such char field");
  1847. data[field.getOffset()] = (byte)(value >> 8);
  1848. data[field.getOffset()+1] = (byte)(value);
  1849. }
  1850. /**
  1851. * Put the value of the named byte field into the persistent fields.
  1852. *
  1853. * @param name the name of the serializable field
  1854. * @param value the value to assign to the field
  1855. * @throws IllegalArgumentException if specified field does not exist
  1856. * or the type of the field does not match the type of
  1857. * <code>value</code>
  1858. */
  1859. public void put(String name, byte value) {
  1860. ObjectStreamField field = desc.getField(name, Byte.TYPE);
  1861. if (field == null || field.getType() != Byte.TYPE)
  1862. throw new IllegalArgumentException("No such byte field");
  1863. data[field.getOffset()] = value;
  1864. }
  1865. /**
  1866. * Put the value of the named short field into the persistent fields.
  1867. *
  1868. * @param name the name of the serializable field
  1869. * @param value the value to assign to the field
  1870. * @throws IllegalArgumentException if specified field does not exist
  1871. * or the type of the field does not match the type of
  1872. * <code>value</code>
  1873. */
  1874. public void put(String name, short value) {
  1875. ObjectStreamField field = desc.getField(name, Short.TYPE);
  1876. if (field == null || field.getType() != Short.TYPE)
  1877. throw new IllegalArgumentException("No such short field");
  1878. int loffset = field.getOffset();
  1879. data[loffset] = (byte)(value >> 8);
  1880. data[loffset+1] = (byte)(value);
  1881. }
  1882. /**
  1883. * Put the value of the named int field into the persistent fields.
  1884. *
  1885. * @param name the name of the serializable field
  1886. * @param value the value to assign to the field
  1887. * @throws IllegalArgumentException if specified field does not exist
  1888. * or the type of the field does not match the type of
  1889. * <code>value</code>
  1890. */
  1891. public void put(String name, int value) {
  1892. ObjectStreamField field = desc.getField(name, Integer.TYPE);
  1893. if (field == null || field.getType() != Integer.TYPE)
  1894. throw new IllegalArgumentException("No such int field");
  1895. int loffset = field.getOffset();
  1896. data[loffset] = (byte)(value >> 24);
  1897. data[loffset+1] = (byte)(value >> 16);
  1898. data[loffset+2] = (byte)(value >> 8);
  1899. data[loffset+3] = (byte)value;
  1900. }
  1901. /**
  1902. * Put the value of the named long field into the persistent fields.
  1903. *
  1904. * @param name the name of the serializable field
  1905. * @param value the value to assign to the field
  1906. * @throws IllegalArgumentException if specified field does not exist
  1907. * or the type of the field does not match the type of
  1908. * <code>value</code>
  1909. */
  1910. public void put(String name, long value) {
  1911. ObjectStreamField field = desc.getField(name, Long.TYPE);
  1912. if (field == null || field.getType() != Long.TYPE)
  1913. throw new IllegalArgumentException("No such long field");
  1914. int loffset = field.getOffset();
  1915. data[loffset] = (byte)(value >> 56);
  1916. data[loffset+1] = (byte)(value >> 48);
  1917. data[loffset+2] = (byte)(value >> 40);
  1918. data[loffset+3] = (byte)(value >> 32);
  1919. data[loffset+4] = (byte)(value >> 24);
  1920. data[loffset+5] = (byte)(value >> 16);
  1921. data[loffset+6] = (byte)(value >> 8);
  1922. data[loffset+7] = (byte)value;
  1923. }
  1924. /**
  1925. * Put the value of the named float field into the persistent fields.
  1926. *
  1927. * @param name the name of the serializable field
  1928. * @param value the value to assign to the field
  1929. * @throws IllegalArgumentException if specified field does not exist
  1930. * or the type of the field does not match the type of
  1931. * <code>value</code>
  1932. */
  1933. public void put(String name, float value) {
  1934. int val = Float.floatToIntBits(value);
  1935. ObjectStreamField field = desc.getField(name, Float.TYPE);
  1936. if (field == null || field.getType() != Float.TYPE)
  1937. throw new IllegalArgumentException("No such float field");
  1938. int loffset = field.getOffset();
  1939. data[loffset] = (byte)(val >> 24);
  1940. data[loffset+1] = (byte)(val >> 16);
  1941. data[loffset+2] = (byte)(val >> 8);
  1942. data[loffset+3] = (byte)val;
  1943. }
  1944. /**
  1945. * Put the value of the named double field into the persistent field.
  1946. *
  1947. * @param name the name of the serializable field
  1948. * @param value the value to assign to the field
  1949. * @throws IllegalArgumentException if specified field does not exist
  1950. * or the type of the field does not match the type of
  1951. * <code>value</code>
  1952. */
  1953. public void put(String name, double value) {
  1954. long val = Double.doubleToLongBits(value);
  1955. ObjectStreamField field = desc.getField(name, Double.TYPE);
  1956. if (field == null || field.getType() != Double.TYPE)
  1957. throw new IllegalArgumentException("No such double field");
  1958. int loffset = field.getOffset();
  1959. data[loffset] = (byte)(val >> 56);
  1960. data[loffset+1] = (byte)(val >> 48);
  1961. data[loffset+2] = (byte)(val >> 40);
  1962. data[loffset+3] = (byte)(val >> 32);
  1963. data[loffset+4] = (byte)(val >> 24);
  1964. data[loffset+5] = (byte)(val >> 16);
  1965. data[loffset+6] = (byte)(val >> 8);
  1966. data[loffset+7] = (byte)val;
  1967. }
  1968. /**
  1969. * Put the value of the named Object field into the persistent field.
  1970. *
  1971. * @param name the name of the serializable field
  1972. * @param value the value to assign to the field
  1973. * @throws IllegalArgumentException if specified field does not exist
  1974. * or the type of the field does not match the type of
  1975. * <code>value</code>
  1976. */
  1977. public void put(String name, Object value) {
  1978. ObjectStreamField field = desc.getField(name, Object.class);
  1979. if (field == null || field.isPrimitive())
  1980. throw new IllegalArgumentException("No such object field");
  1981. objects[field.getOffset()] = value;
  1982. }
  1983. /**
  1984. * Write the data and fields to the specified stream.
  1985. *
  1986. * @param out the stream to write the data and fields to
  1987. * @throws IOException if I/O errors occur while writing to the
  1988. * underlying stream
  1989. */
  1990. public void write(ObjectOutput out) throws IOException {
  1991. if (data != null)
  1992. out.write(data, 0, data.length);
  1993. if (objects != null) {
  1994. for (int i = 0; i < objects.length; i++)
  1995. out.writeObject(objects[i]);
  1996. }
  1997. }
  1998. /**
  1999. * Create a PutField object for the a Class.
  2000. * Allocate the arrays for primitives and objects.
  2001. */
  2002. PutFieldImpl(ObjectStreamClass descriptor) {
  2003. desc = descriptor;
  2004. if (desc.numPrimBytes > 0)
  2005. data = new byte[desc.numPrimBytes];
  2006. if (desc.numObjFields > 0)
  2007. objects = new Object[desc.numObjFields];
  2008. }
  2009. /*
  2010. * The byte array that contains the bytes for the primitive fields.
  2011. * The Object array that contains the objects for the object fields.
  2012. */
  2013. private byte[] data;
  2014. private Object[] objects;
  2015. private ObjectStreamClass desc;
  2016. };
  2017. /*************************************************************/
  2018. /* Remember the first exception that stopped this stream. */
  2019. private IOException abortIOException = null;
  2020. /* Object references are mapped to the wire handles through a hashtable
  2021. * WireHandles are integers generated by the ObjectOutputStream,
  2022. * they need only be unique within a stream.
  2023. */
  2024. private HandleTable handleTable;
  2025. /* The object is the current object and ClassDescriptor is the current
  2026. * subclass of the object being written. Nesting information is kept
  2027. * on the stack.
  2028. */
  2029. private Object currentObject;
  2030. private ObjectStreamClass currentClassDesc;
  2031. private Stack classDescStack;
  2032. private PutField currentPutFields;
  2033. private Object[] writeObjectArglist = {this};
  2034. /*
  2035. * Primitive data is fetched from objects and stored in
  2036. * this array prior to writing. The array is allocated prior to first use.
  2037. */
  2038. private static final int INITIAL_BUFFER_SIZE = 64;
  2039. private byte[] data;
  2040. /* Buffer for writing strings. */
  2041. private static final int CDATA_MAX_LEN = 1024;
  2042. private char[] cdata;
  2043. /*
  2044. * Flag set to true to allow replaceObject to be called.
  2045. * Set by enableReplaceObject.
  2046. * Identity hash table mapping objects to their replacements.
  2047. */
  2048. boolean enableReplace;
  2049. private ReplaceTable replaceTable;
  2050. static final private boolean REPLACEABLE = true;
  2051. static final private boolean NOT_REPLACEABLE = false;
  2052. /* Recursion level, starts at zero and is incremented for each entry
  2053. * to writeObject. Decremented before exit.
  2054. */
  2055. private int recursionDepth = 0;
  2056. /* If true, use JDK 1.1 Externalizable data format. */
  2057. boolean useDeprecatedExternalizableFormat = false;
  2058. /* if true, override writeObject implementation with writeObjectOverride.
  2059. */
  2060. private boolean enableSubclassImplementation;
  2061. /**
  2062. * Lightweight hash table mapping objects to their corresponding wire
  2063. * handles.
  2064. */
  2065. private static final class HandleTable {
  2066. private int nextWireOffset; // next free wire handle offset
  2067. private int wireHashCapacity; // when to grow hash table next
  2068. private float loadFactor; // factor for computing capacity
  2069. private int[] wireHash2Handle; // hash spine
  2070. private int[] wireNextHandle; // next hash entry
  2071. private Object[] wireHandle2Object; // handle -> object mapping
  2072. /**
  2073. * Constructs handle table with given capacity and load factor.
  2074. */
  2075. public HandleTable(int initialCapacity, float loadFactor) {
  2076. this.loadFactor = loadFactor;
  2077. wireHash2Handle = new int[initialCapacity];
  2078. wireNextHandle = new int[initialCapacity];
  2079. wireHandle2Object = new Object[initialCapacity];
  2080. wireHashCapacity = (int) (initialCapacity * loadFactor);
  2081. clear();
  2082. }
  2083. /**
  2084. * Add an object to the handle table, assigning it the next available
  2085. * wire handle offset. Returns the value of the wire handle offset
  2086. * assigned to the object.
  2087. */
  2088. public int assignWireOffset(Object obj) {
  2089. if (nextWireOffset >= wireNextHandle.length)
  2090. growEntries();
  2091. if (nextWireOffset >= wireHashCapacity)
  2092. growSpine();
  2093. insert(obj, nextWireOffset);
  2094. return nextWireOffset++;
  2095. }
  2096. /**
  2097. * Insert new element into hash table. This is only called when checks
  2098. * have already been performed to ensure that the hash table is large
  2099. * enough.
  2100. */
  2101. private void insert(Object obj, int offset) {
  2102. int index = (System.identityHashCode(obj) & 0x7FFFFFFF) %
  2103. wireHash2Handle.length;
  2104. wireHandle2Object[offset] = obj;
  2105. wireNextHandle[offset] = wireHash2Handle[index];
  2106. wireHash2Handle[index] = offset;
  2107. }
  2108. /**
  2109. * Double the size of the hash table spine.
  2110. */
  2111. private void growSpine() {
  2112. wireHash2Handle = new int[(wireHash2Handle.length << 1) + 1];
  2113. wireHashCapacity = (int) (wireHash2Handle.length * loadFactor);
  2114. Arrays.fill(wireHash2Handle, -1);
  2115. for (int i = 0; i < nextWireOffset; i++) {
  2116. insert(wireHandle2Object[i], i);
  2117. }
  2118. }
  2119. /**
  2120. * Double the number of hash table entry spaces.
  2121. */
  2122. private void growEntries() {
  2123. int[] newWireNextHandle = new int[wireNextHandle.length * 2];
  2124. System.arraycopy(wireNextHandle, 0, newWireNextHandle, 0,
  2125. nextWireOffset);
  2126. wireNextHandle = newWireNextHandle;
  2127. Object[] newWireHandle2Object =
  2128. new Object[wireHandle2Object.length * 2];
  2129. System.arraycopy(wireHandle2Object, 0, newWireHandle2Object, 0,
  2130. nextWireOffset);
  2131. wireHandle2Object = newWireHandle2Object;
  2132. }
  2133. /**
  2134. * Returns the wire handle offset associated with the given object, or
  2135. * -1 if not found.
  2136. */
  2137. public int findWireOffset(Object obj) {
  2138. int index = (System.identityHashCode(obj) & 0x7FFFFFFF) %
  2139. wireHash2Handle.length;
  2140. for (int handle = wireHash2Handle[index];
  2141. handle >= 0;
  2142. handle = wireNextHandle[handle]) {
  2143. if (wireHandle2Object[handle] == obj)
  2144. return handle;
  2145. }
  2146. return -1;
  2147. }
  2148. /**
  2149. * Empties all mappings from this handle table, resets next available
  2150. * wire handle offset.
  2151. */
  2152. public void clear() {
  2153. Arrays.fill(wireHash2Handle, -1);
  2154. Arrays.fill(wireHandle2Object, 0, nextWireOffset, null);
  2155. nextWireOffset = 0;
  2156. }
  2157. /**
  2158. * Return number of entries currently in handle table.
  2159. */
  2160. public int size() {
  2161. return nextWireOffset;
  2162. }
  2163. }
  2164. /**
  2165. * Lightweight identity hash table mapping objects to corresponding
  2166. * replacement objects.
  2167. */
  2168. private static final class ReplaceTable {
  2169. private HandleTable htab; // maps object -> index
  2170. private Object[] reps; // maps index -> replacement object
  2171. /**
  2172. * Creates new replacement table with given capacity and load factor.
  2173. */
  2174. public ReplaceTable(int initialCapacity, float loadFactor) {
  2175. htab = new HandleTable(initialCapacity, loadFactor);
  2176. reps = new Object[initialCapacity];
  2177. }
  2178. /**
  2179. * Enters mapping from object to replacement object.
  2180. */
  2181. public void assign(Object obj, Object rep) {
  2182. int index = htab.assignWireOffset(obj);
  2183. while (index >= reps.length) {
  2184. grow();
  2185. }
  2186. reps[index] = rep;
  2187. }
  2188. /**
  2189. * Looks up and returns replacement for given object. If no
  2190. * replacement is found, returns the lookup object itself.
  2191. */
  2192. public Object lookup(Object obj) {
  2193. int index = htab.findWireOffset(obj);
  2194. return (index >= 0) ? reps[index] : obj;
  2195. }
  2196. /**
  2197. * Resets table to its initial (empty) state.
  2198. */
  2199. public void clear() {
  2200. Arrays.fill(reps, 0, htab.size(), null);
  2201. htab.clear();
  2202. }
  2203. /**
  2204. * Returns the number of mappings currently in table.
  2205. */
  2206. public int size() {
  2207. return htab.size();
  2208. }
  2209. /**
  2210. * Increases table capacity.
  2211. */
  2212. private void grow() {
  2213. Object[] newReps = new Object[(reps.length << 1) + 1];
  2214. System.arraycopy(reps, 0, newReps, 0, reps.length);
  2215. reps = newReps;
  2216. }
  2217. }
  2218. /**
  2219. * Unsynchronized Stack.
  2220. */
  2221. private static final class Stack extends ArrayList {
  2222. // use serialVersionUID from JDK 1.2.2 for interoperability
  2223. private static final long serialVersionUID = -428799992207134975L;
  2224. public void setSize(int newSize) {
  2225. if (newSize == 0) {
  2226. clear();
  2227. } else {
  2228. int len = size();
  2229. for (int i = len - 1; i >= newSize; i--) {
  2230. remove(i);
  2231. }
  2232. }
  2233. }
  2234. public Object push(Object item) {
  2235. add(item);
  2236. return item;
  2237. }
  2238. /**
  2239. * Removes the object at the top of this stack and returns that
  2240. * object as the value of this function.
  2241. *
  2242. * @return The object at the top of this stack (the last item
  2243. * of the <tt>Vector</tt> object).
  2244. * @exception EmptyStackException if this stack is empty.
  2245. */
  2246. public Object pop() {
  2247. Object obj;
  2248. int len = size();
  2249. obj = peek();
  2250. remove(len - 1);
  2251. return obj;
  2252. }
  2253. /**
  2254. * Looks at the object at the top of this stack without removing it
  2255. * from the stack.
  2256. *
  2257. * @return the object at the top of this stack (the last item
  2258. * of the <tt>Vector</tt> object).
  2259. * @exception EmptyStackException if this stack is empty.
  2260. */
  2261. public Object peek() {
  2262. int len = size();
  2263. if (len == 0)
  2264. throw new java.util.EmptyStackException();
  2265. return get(len - 1);
  2266. }
  2267. }
  2268. };