DataOutputStream.java 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. /* DataOutputStream.java -- Writes primitive Java datatypes to streams
  2. Copyright (C) 1998, 2001, 2003, 2005, 2008 Free Software Foundation, Inc.
  3. This file is part of GNU Classpath.
  4. GNU Classpath is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.
  8. GNU Classpath is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNU Classpath; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  15. 02110-1301 USA.
  16. Linking this library statically or dynamically with other modules is
  17. making a combined work based on this library. Thus, the terms and
  18. conditions of the GNU General Public License cover the whole
  19. combination.
  20. As a special exception, the copyright holders of this library give you
  21. permission to link this library with independent modules to produce an
  22. executable, regardless of the license terms of these independent
  23. modules, and to copy and distribute the resulting executable under
  24. terms of your choice, provided that you also meet, for each linked
  25. independent module, the terms and conditions of the license of that
  26. module. An independent module is a module which is not derived from
  27. or based on this library. If you modify this library, you may extend
  28. this exception to your version of the library, but you are not
  29. obligated to do so. If you do not wish to do so, delete this
  30. exception statement from your version. */
  31. package java.io;
  32. /* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
  33. * "The Java Language Specification", ISBN 0-201-63451-1
  34. * Status: Complete to version 1.1.
  35. */
  36. /**
  37. * This class provides a mechanism for writing primitive Java datatypes
  38. * to an <code>OutputStream</code> in a portable way. Data written to
  39. * a stream using this class can be read back in using the
  40. * <code>DataInputStream</code> class on any platform.
  41. *
  42. * @see DataInputStream
  43. *
  44. * @author Aaron M. Renn (arenn@urbanophile.com)
  45. * @author Tom Tromey (tromey@cygnus.com)
  46. */
  47. public class DataOutputStream extends FilterOutputStream implements DataOutput
  48. {
  49. /**
  50. * This is the total number of bytes that have been written to the
  51. * stream by this object instance.
  52. */
  53. protected int written;
  54. /**
  55. * Utf8 byte buffer, used by writeUTF()
  56. */
  57. private byte[] buf;
  58. /**
  59. * This method initializes an instance of <code>DataOutputStream</code> to
  60. * write its data to the specified underlying <code>OutputStream</code>
  61. *
  62. * @param out The subordinate <code>OutputStream</code> to which this
  63. * object will write
  64. */
  65. public DataOutputStream (OutputStream out)
  66. {
  67. super (out);
  68. written = 0;
  69. }
  70. /**
  71. * This method flushes any unwritten bytes to the underlying stream.
  72. *
  73. * @exception IOException If an error occurs.
  74. */
  75. public void flush () throws IOException
  76. {
  77. out.flush();
  78. }
  79. /**
  80. * This method returns the total number of bytes that have been written to
  81. * the underlying output stream so far. This is the value of the
  82. * <code>written</code> instance variable
  83. *
  84. * @return The number of bytes written to the stream.
  85. */
  86. public final int size ()
  87. {
  88. return written;
  89. }
  90. /**
  91. * This method writes the specified byte (passed as an <code>int</code>)
  92. * to the underlying output stream.
  93. *
  94. * @param value The <code>byte</code> to write, passed as an <code>int</code>.
  95. *
  96. * @exception IOException If an error occurs.
  97. */
  98. public synchronized void write (int value) throws IOException
  99. {
  100. out.write (value);
  101. ++written;
  102. }
  103. /**
  104. * This method writes <code>len</code> bytes from the specified byte array
  105. * <code>buf</code> starting at position <code>offset</code> into the
  106. * buffer to the underlying output stream.
  107. *
  108. * @param buf The byte array to write from.
  109. * @param offset The index into the byte array to start writing from.
  110. * @param len The number of bytes to write.
  111. *
  112. * @exception IOException If an error occurs.
  113. */
  114. public synchronized void write (byte[] buf, int offset, int len)
  115. throws IOException
  116. {
  117. out.write(buf, offset, len);
  118. written += len;
  119. }
  120. /**
  121. * This method writes a Java boolean value to an output stream. If
  122. * <code>value</code> is <code>true</code>, a byte with the value of
  123. * 1 will be written, otherwise a byte with the value of 0 will be
  124. * written.
  125. *
  126. * The value written can be read using the <code>readBoolean</code>
  127. * method in <code>DataInput</code>.
  128. *
  129. * @param value The <code>boolean</code> value to write to the stream
  130. *
  131. * @exception IOException If an error occurs
  132. *
  133. * @see DataInput#readBoolean
  134. */
  135. public final void writeBoolean (boolean value) throws IOException
  136. {
  137. write (value ? 1 : 0);
  138. }
  139. /**
  140. * This method writes a Java byte value to an output stream. The
  141. * byte to be written will be in the lowest 8 bits of the
  142. * <code>int</code> value passed.
  143. *
  144. * The value written can be read using the <code>readByte</code> or
  145. * <code>readUnsignedByte</code> methods in <code>DataInput</code>.
  146. *
  147. * @param value The <code>byte</code> to write to the stream, passed as
  148. * the low eight bits of an <code>int</code>.
  149. *
  150. * @exception IOException If an error occurs
  151. *
  152. * @see DataInput#readByte
  153. * @see DataInput#readUnsignedByte
  154. */
  155. public final void writeByte (int value) throws IOException
  156. {
  157. write (value & 0xff);
  158. }
  159. /**
  160. * This method writes a Java short value to an output stream. The
  161. * char to be written will be in the lowest 16 bits of the <code>int</code>
  162. * value passed. These bytes will be written "big endian". That is,
  163. * with the high byte written first in the following manner:
  164. * <p>
  165. * <code>byte0 = (byte)((value & 0xFF00) >> 8);<br>
  166. * byte1 = (byte)(value & 0x00FF);</code>
  167. * <p>
  168. *
  169. * The value written can be read using the <code>readShort</code> and
  170. * <code>readUnsignedShort</code> methods in <code>DataInput</code>.
  171. *
  172. * @param value The <code>short</code> value to write to the stream,
  173. * passed as an <code>int</code>.
  174. *
  175. * @exception IOException If an error occurs
  176. *
  177. * @see DataInput#readShort
  178. * @see DataInput#readUnsignedShort
  179. */
  180. public final synchronized void writeShort (int value) throws IOException
  181. {
  182. write ((byte) (0xff & (value >> 8)));
  183. write ((byte) (0xff & value));
  184. }
  185. /**
  186. * This method writes a Java char value to an output stream. The
  187. * char to be written will be in the lowest 16 bits of the <code>int</code>
  188. * value passed. These bytes will be written "big endian". That is,
  189. * with the high byte written first in the following manner:
  190. * <p>
  191. * <code>byte0 = (byte)((value & 0xFF00) >> 8);<br>
  192. * byte1 = (byte)(value & 0x00FF);</code>
  193. * <p>
  194. *
  195. * The value written can be read using the <code>readChar</code>
  196. * method in <code>DataInput</code>.
  197. *
  198. * @param value The <code>char</code> value to write,
  199. * passed as an <code>int</code>.
  200. *
  201. * @exception IOException If an error occurs
  202. *
  203. * @see DataInput#readChar
  204. */
  205. public final synchronized void writeChar (int value) throws IOException
  206. {
  207. write ((byte) (0xff & (value >> 8)));
  208. write ((byte) (0xff & value));
  209. }
  210. /**
  211. * This method writes a Java int value to an output stream. The 4 bytes
  212. * of the passed value will be written "big endian". That is, with
  213. * the high byte written first in the following manner:
  214. * <p>
  215. * <code>byte0 = (byte)((value & 0xFF000000) >> 24);<br>
  216. * byte1 = (byte)((value & 0x00FF0000) >> 16);<br>
  217. * byte2 = (byte)((value & 0x0000FF00) >> 8);<br>
  218. * byte3 = (byte)(value & 0x000000FF);</code>
  219. * <p>
  220. *
  221. * The value written can be read using the <code>readInt</code>
  222. * method in <code>DataInput</code>.
  223. *
  224. * @param value The <code>int</code> value to write to the stream
  225. *
  226. * @exception IOException If an error occurs
  227. *
  228. * @see DataInput#readInt
  229. */
  230. public final synchronized void writeInt (int value) throws IOException
  231. {
  232. write ((byte) (0xff & (value >> 24)));
  233. write ((byte) (0xff & (value >> 16)));
  234. write ((byte) (0xff & (value >> 8)));
  235. write ((byte) (0xff & value));
  236. }
  237. /**
  238. * This method writes a Java long value to an output stream. The 8 bytes
  239. * of the passed value will be written "big endian". That is, with
  240. * the high byte written first in the following manner:
  241. * <p>
  242. * <code>byte0 = (byte)((value & 0xFF00000000000000L) >> 56);<br>
  243. * byte1 = (byte)((value & 0x00FF000000000000L) >> 48);<br>
  244. * byte2 = (byte)((value & 0x0000FF0000000000L) >> 40);<br>
  245. * byte3 = (byte)((value & 0x000000FF00000000L) >> 32);<br>
  246. * byte4 = (byte)((value & 0x00000000FF000000L) >> 24);<br>
  247. * byte5 = (byte)((value & 0x0000000000FF0000L) >> 16);<br>
  248. * byte6 = (byte)((value & 0x000000000000FF00L) >> 8);<br>
  249. * byte7 = (byte)(value & 0x00000000000000FFL);</code>
  250. * <p>
  251. *
  252. * The value written can be read using the <code>readLong</code>
  253. * method in <code>DataInput</code>.
  254. *
  255. * @param value The <code>long</code> value to write to the stream
  256. *
  257. * @exception IOException If an error occurs
  258. *
  259. * @see DataInput#readLong
  260. */
  261. public final synchronized void writeLong (long value) throws IOException
  262. {
  263. write ((byte) (0xff & (value >> 56)));
  264. write ((byte) (0xff & (value>> 48)));
  265. write ((byte) (0xff & (value>> 40)));
  266. write ((byte) (0xff & (value>> 32)));
  267. write ((byte) (0xff & (value>> 24)));
  268. write ((byte) (0xff & (value>> 16)));
  269. write ((byte) (0xff & (value>> 8)));
  270. write ((byte) (0xff & value));
  271. }
  272. /**
  273. * This method writes a Java <code>float</code> value to the stream. This
  274. * value is written by first calling the method
  275. * <code>Float.floatToIntBits</code>
  276. * to retrieve an <code>int</code> representing the floating point number,
  277. * then writing this <code>int</code> value to the stream exactly the same
  278. * as the <code>writeInt()</code> method does.
  279. *
  280. * The value written can be read using the <code>readFloat</code>
  281. * method in <code>DataInput</code>.
  282. *
  283. * @param value The <code>float</code> value to write to the stream
  284. *
  285. * @exception IOException If an error occurs
  286. *
  287. * @see #writeInt(int)
  288. * @see DataInput#readFloat
  289. * @see Float#floatToIntBits
  290. */
  291. public final void writeFloat (float value) throws IOException
  292. {
  293. writeInt (Float.floatToIntBits (value));
  294. }
  295. /**
  296. * This method writes a Java <code>double</code> value to the stream. This
  297. * value is written by first calling the method
  298. * <code>Double.doubleToLongBits</code>
  299. * to retrieve an <code>long</code> representing the floating point number,
  300. * then writing this <code>long</code> value to the stream exactly the same
  301. * as the <code>writeLong()</code> method does.
  302. *
  303. * The value written can be read using the <code>readDouble</code>
  304. * method in <code>DataInput</code>.
  305. *
  306. * @param value The <code>double</code> value to write to the stream
  307. *
  308. * @exception IOException If an error occurs
  309. *
  310. * @see #writeLong(long)
  311. * @see DataInput#readDouble
  312. * @see Double#doubleToLongBits
  313. */
  314. public final void writeDouble (double value) throws IOException
  315. {
  316. writeLong (Double.doubleToLongBits (value));
  317. }
  318. /**
  319. * This method writes all the bytes in a <code>String</code> out to the
  320. * stream. One byte is written for each character in the
  321. * <code>String</code>.
  322. * The high eight bits of each character are discarded, thus this
  323. * method is inappropriate for completely representing Unicode characters.
  324. *
  325. * @param value The <code>String</code> to write to the stream
  326. *
  327. * @exception IOException If an error occurs
  328. */
  329. public final void writeBytes (String value) throws IOException
  330. {
  331. int len = value.length();
  332. for (int i = 0; i < len; ++i)
  333. writeByte (value.charAt(i));
  334. }
  335. /**
  336. * This method writes all the characters of a <code>String</code> to an
  337. * output stream as an array of <code>char</code>'s. Each character
  338. * is written using the method specified in the <code>writeChar</code>
  339. * method.
  340. *
  341. * @param value The <code>String</code> to write to the stream
  342. *
  343. * @exception IOException If an error occurs
  344. *
  345. * @see #writeChar(char)
  346. */
  347. public final void writeChars (String value) throws IOException
  348. {
  349. int len = value.length();
  350. for (int i = 0; i < len; ++i)
  351. writeChar (value.charAt(i));
  352. }
  353. /**
  354. * Calculate the length, in bytes, of a <code>String</code> in Utf8 format.
  355. * This method is package-private so that <code>ObjectOutputStream</code>
  356. * may use it. The return type is long so that a long string whose
  357. * Utf8 byte count is 64 bit long may be handled.
  358. *
  359. * @param value The <code>String</code> to measure
  360. * @param start String index at which to begin count
  361. * @param sum Starting Utf8 byte count
  362. *
  363. */
  364. long getUTFlength(String value, int start, long sum)
  365. {
  366. int len = value.length();
  367. for (int i = start; i < len; ++i)
  368. {
  369. char c = value.charAt(i);
  370. if (c >= '\u0001' && c <= '\u007f')
  371. sum += 1;
  372. else if (c == '\u0000' || (c >= '\u0080' && c <= '\u07ff'))
  373. sum += 2;
  374. else
  375. sum += 3;
  376. }
  377. return sum;
  378. }
  379. /**
  380. * This method writes a Java <code>String</code> to the stream in a modified
  381. * UTF-8 format. First, two bytes are written to the stream indicating the
  382. * number of bytes to follow. Note that this is the number of bytes in the
  383. * encoded <code>String</code> not the <code>String</code> length. Next
  384. * come the encoded characters. Each character in the <code>String</code>
  385. * is encoded as either one, two or three bytes. For characters in the
  386. * range of <code>\u0001</code> to <\u007F>, one byte is used. The character
  387. * value goes into bits 0-7 and bit eight is 0. For characters in the range
  388. * of <code>\u0080</code> to <code>\u007FF</code>, two bytes are used. Bits
  389. * 6-10 of the character value are encoded bits 0-4 of the first byte, with
  390. * the high bytes having a value of "110". Bits 0-5 of the character value
  391. * are stored in bits 0-5 of the second byte, with the high bits set to
  392. * "10". This type of encoding is also done for the null character
  393. * <code>\u0000</code>. This eliminates any C style NUL character values
  394. * in the output. All remaining characters are stored as three bytes.
  395. * Bits 12-15 of the character value are stored in bits 0-3 of the first
  396. * byte. The high bits of the first bytes are set to "1110". Bits 6-11
  397. * of the character value are stored in bits 0-5 of the second byte. The
  398. * high bits of the second byte are set to "10". And bits 0-5 of the
  399. * character value are stored in bits 0-5 of byte three, with the high bits
  400. * of that byte set to "10".
  401. *
  402. * The value written can be read using the <code>readUTF</code>
  403. * method in <code>DataInput</code>.
  404. *
  405. * @param value The <code>String</code> to write to the output in UTF format
  406. *
  407. * @exception IOException If an error occurs
  408. *
  409. * @see DataInput#readUTF
  410. */
  411. public final synchronized void writeUTF(String value) throws IOException
  412. {
  413. long l = getUTFlength(value, 0, 0);
  414. if (l > 65535)
  415. throw new UTFDataFormatException ();
  416. writeUTFShort(value, (int)l);
  417. }
  418. /**
  419. * This method performs the main task of <code>writeUTF</code>.
  420. * This method is package-private because ObjectOutputStream uses it.
  421. *
  422. * @param value The <code>String</code> to write to the output in UTF format
  423. *
  424. * @param bytelen The UTF-8 byte length of the <code>String</code>. When
  425. * this method is called, the expected byte length must have been calculated
  426. * by <code>getUTFlength</code>.
  427. *
  428. * @exception IOException If an error occurs
  429. *
  430. * @see DataInput#readUTF
  431. */
  432. final synchronized void writeUTFShort(String value, int bytelen)
  433. throws IOException
  434. {
  435. writeShort(bytelen);
  436. writeUTFBytes(value);
  437. }
  438. /**
  439. * This method is similar to <code>writeUTF</code>, but it writes the
  440. * UTF-8 byte length in 64 bits.
  441. * This method is not public but <code>ObjectOutputStream</code> uses it.
  442. *
  443. * @param value The <code>String</code> to write to the output in UTF format
  444. *
  445. * @param bytelen The UTF-8 byte length of the <code>String</code>. When
  446. * this method is called, the expected byte length must have been calculated
  447. * by <code>getUTFlength</code>.
  448. *
  449. * @exception IOException If an error occurs
  450. *
  451. */
  452. final synchronized void writeUTFLong(String value, long bytelen)
  453. throws IOException
  454. {
  455. writeLong(bytelen);
  456. writeUTFBytes(value);
  457. }
  458. /**
  459. * This method performes the main task of <code>writeUTF</code> and
  460. * <code>WriteUTFLong</code>, which is to write the UTF-8 byte
  461. * sequence to the output.
  462. *
  463. * @param value The <code>String</code> to write to the output in UTF format
  464. *
  465. * @exception IOException If an error occurs
  466. *
  467. */
  468. private final synchronized void writeUTFBytes(String value)
  469. throws IOException
  470. {
  471. int len = value.length();
  472. int i = 0;
  473. int pos = 0;
  474. if (buf == null)
  475. buf = new byte[512];
  476. do
  477. {
  478. while (i < len && pos < buf.length - 3)
  479. {
  480. char c = value.charAt(i++);
  481. if (c >= '\u0001' && c <= '\u007f')
  482. buf[pos++] = (byte) c;
  483. else if (c == '\u0000' || (c >= '\u0080' && c <= '\u07ff'))
  484. {
  485. buf[pos++] = (byte) (0xc0 | (0x1f & (c >> 6)));
  486. buf[pos++] = (byte) (0x80 | (0x3f & c));
  487. }
  488. else
  489. {
  490. // JSL says the first byte should be or'd with 0xc0, but
  491. // that is a typo. Unicode says 0xe0, and that is what is
  492. // consistent with DataInputStream.
  493. buf[pos++] = (byte) (0xe0 | (0x0f & (c >> 12)));
  494. buf[pos++] = (byte) (0x80 | (0x3f & (c >> 6)));
  495. buf[pos++] = (byte) (0x80 | (0x3f & c));
  496. }
  497. }
  498. write(buf, 0, pos);
  499. pos = 0;
  500. }
  501. while (i < len);
  502. }
  503. } // class DataOutputStream