1. /*
  2. * @(#)DataOutputStream.java 1.43 04/05/13
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.io;
  8. /**
  9. * A data output stream lets an application write primitive Java data
  10. * types to an output stream in a portable way. An application can
  11. * then use a data input stream to read the data back in.
  12. *
  13. * @author unascribed
  14. * @version 1.43, 05/13/04
  15. * @see java.io.DataInputStream
  16. * @since JDK1.0
  17. */
  18. public
  19. class DataOutputStream extends FilterOutputStream implements DataOutput {
  20. /**
  21. * The number of bytes written to the data output stream so far.
  22. * If this counter overflows, it will be wrapped to Integer.MAX_VALUE.
  23. */
  24. protected int written;
  25. /**
  26. * bytearr is initialized on demand by writeUTF
  27. */
  28. private byte[] bytearr = null;
  29. /**
  30. * Creates a new data output stream to write data to the specified
  31. * underlying output stream. The counter <code>written</code> is
  32. * set to zero.
  33. *
  34. * @param out the underlying output stream, to be saved for later
  35. * use.
  36. * @see java.io.FilterOutputStream#out
  37. */
  38. public DataOutputStream(OutputStream out) {
  39. super(out);
  40. }
  41. /**
  42. * Increases the written counter by the specified value
  43. * until it reaches Integer.MAX_VALUE.
  44. */
  45. private void incCount(int value) {
  46. int temp = written + value;
  47. if (temp < 0) {
  48. temp = Integer.MAX_VALUE;
  49. }
  50. written = temp;
  51. }
  52. /**
  53. * Writes the specified byte (the low eight bits of the argument
  54. * <code>b</code>) to the underlying output stream. If no exception
  55. * is thrown, the counter <code>written</code> is incremented by
  56. * <code>1</code>.
  57. * <p>
  58. * Implements the <code>write</code> method of <code>OutputStream</code>.
  59. *
  60. * @param b the <code>byte</code> to be written.
  61. * @exception IOException if an I/O error occurs.
  62. * @see java.io.FilterOutputStream#out
  63. */
  64. public synchronized void write(int b) throws IOException {
  65. out.write(b);
  66. incCount(1);
  67. }
  68. /**
  69. * Writes <code>len</code> bytes from the specified byte array
  70. * starting at offset <code>off</code> to the underlying output stream.
  71. * If no exception is thrown, the counter <code>written</code> is
  72. * incremented by <code>len</code>.
  73. *
  74. * @param b the data.
  75. * @param off the start offset in the data.
  76. * @param len the number of bytes to write.
  77. * @exception IOException if an I/O error occurs.
  78. * @see java.io.FilterOutputStream#out
  79. */
  80. public synchronized void write(byte b[], int off, int len)
  81. throws IOException
  82. {
  83. out.write(b, off, len);
  84. incCount(len);
  85. }
  86. /**
  87. * Flushes this data output stream. This forces any buffered output
  88. * bytes to be written out to the stream.
  89. * <p>
  90. * The <code>flush</code> method of <code>DataOutputStream</code>
  91. * calls the <code>flush</code> method of its underlying output stream.
  92. *
  93. * @exception IOException if an I/O error occurs.
  94. * @see java.io.FilterOutputStream#out
  95. * @see java.io.OutputStream#flush()
  96. */
  97. public void flush() throws IOException {
  98. out.flush();
  99. }
  100. /**
  101. * Writes a <code>boolean</code> to the underlying output stream as
  102. * a 1-byte value. The value <code>true</code> is written out as the
  103. * value <code>(byte)1</code> the value <code>false</code> is
  104. * written out as the value <code>(byte)0</code>. If no exception is
  105. * thrown, the counter <code>written</code> is incremented by
  106. * <code>1</code>.
  107. *
  108. * @param v a <code>boolean</code> value to be written.
  109. * @exception IOException if an I/O error occurs.
  110. * @see java.io.FilterOutputStream#out
  111. */
  112. public final void writeBoolean(boolean v) throws IOException {
  113. out.write(v ? 1 : 0);
  114. incCount(1);
  115. }
  116. /**
  117. * Writes out a <code>byte</code> to the underlying output stream as
  118. * a 1-byte value. If no exception is thrown, the counter
  119. * <code>written</code> is incremented by <code>1</code>.
  120. *
  121. * @param v a <code>byte</code> value to be written.
  122. * @exception IOException if an I/O error occurs.
  123. * @see java.io.FilterOutputStream#out
  124. */
  125. public final void writeByte(int v) throws IOException {
  126. out.write(v);
  127. incCount(1);
  128. }
  129. /**
  130. * Writes a <code>short</code> to the underlying output stream as two
  131. * bytes, high byte first. If no exception is thrown, the counter
  132. * <code>written</code> is incremented by <code>2</code>.
  133. *
  134. * @param v a <code>short</code> to be written.
  135. * @exception IOException if an I/O error occurs.
  136. * @see java.io.FilterOutputStream#out
  137. */
  138. public final void writeShort(int v) throws IOException {
  139. out.write((v >>> 8) & 0xFF);
  140. out.write((v >>> 0) & 0xFF);
  141. incCount(2);
  142. }
  143. /**
  144. * Writes a <code>char</code> to the underlying output stream as a
  145. * 2-byte value, high byte first. If no exception is thrown, the
  146. * counter <code>written</code> is incremented by <code>2</code>.
  147. *
  148. * @param v a <code>char</code> value to be written.
  149. * @exception IOException if an I/O error occurs.
  150. * @see java.io.FilterOutputStream#out
  151. */
  152. public final void writeChar(int v) throws IOException {
  153. out.write((v >>> 8) & 0xFF);
  154. out.write((v >>> 0) & 0xFF);
  155. incCount(2);
  156. }
  157. /**
  158. * Writes an <code>int</code> to the underlying output stream as four
  159. * bytes, high byte first. If no exception is thrown, the counter
  160. * <code>written</code> is incremented by <code>4</code>.
  161. *
  162. * @param v an <code>int</code> to be written.
  163. * @exception IOException if an I/O error occurs.
  164. * @see java.io.FilterOutputStream#out
  165. */
  166. public final void writeInt(int v) throws IOException {
  167. out.write((v >>> 24) & 0xFF);
  168. out.write((v >>> 16) & 0xFF);
  169. out.write((v >>> 8) & 0xFF);
  170. out.write((v >>> 0) & 0xFF);
  171. incCount(4);
  172. }
  173. private byte writeBuffer[] = new byte[8];
  174. /**
  175. * Writes a <code>long</code> to the underlying output stream as eight
  176. * bytes, high byte first. In no exception is thrown, the counter
  177. * <code>written</code> is incremented by <code>8</code>.
  178. *
  179. * @param v a <code>long</code> to be written.
  180. * @exception IOException if an I/O error occurs.
  181. * @see java.io.FilterOutputStream#out
  182. */
  183. public final void writeLong(long v) throws IOException {
  184. writeBuffer[0] = (byte)(v >>> 56);
  185. writeBuffer[1] = (byte)(v >>> 48);
  186. writeBuffer[2] = (byte)(v >>> 40);
  187. writeBuffer[3] = (byte)(v >>> 32);
  188. writeBuffer[4] = (byte)(v >>> 24);
  189. writeBuffer[5] = (byte)(v >>> 16);
  190. writeBuffer[6] = (byte)(v >>> 8);
  191. writeBuffer[7] = (byte)(v >>> 0);
  192. out.write(writeBuffer, 0, 8);
  193. incCount(8);
  194. }
  195. /**
  196. * Converts the float argument to an <code>int</code> using the
  197. * <code>floatToIntBits</code> method in class <code>Float</code>,
  198. * and then writes that <code>int</code> value to the underlying
  199. * output stream as a 4-byte quantity, high byte first. If no
  200. * exception is thrown, the counter <code>written</code> is
  201. * incremented by <code>4</code>.
  202. *
  203. * @param v a <code>float</code> value to be written.
  204. * @exception IOException if an I/O error occurs.
  205. * @see java.io.FilterOutputStream#out
  206. * @see java.lang.Float#floatToIntBits(float)
  207. */
  208. public final void writeFloat(float v) throws IOException {
  209. writeInt(Float.floatToIntBits(v));
  210. }
  211. /**
  212. * Converts the double argument to a <code>long</code> using the
  213. * <code>doubleToLongBits</code> method in class <code>Double</code>,
  214. * and then writes that <code>long</code> value to the underlying
  215. * output stream as an 8-byte quantity, high byte first. If no
  216. * exception is thrown, the counter <code>written</code> is
  217. * incremented by <code>8</code>.
  218. *
  219. * @param v a <code>double</code> value to be written.
  220. * @exception IOException if an I/O error occurs.
  221. * @see java.io.FilterOutputStream#out
  222. * @see java.lang.Double#doubleToLongBits(double)
  223. */
  224. public final void writeDouble(double v) throws IOException {
  225. writeLong(Double.doubleToLongBits(v));
  226. }
  227. /**
  228. * Writes out the string to the underlying output stream as a
  229. * sequence of bytes. Each character in the string is written out, in
  230. * sequence, by discarding its high eight bits. If no exception is
  231. * thrown, the counter <code>written</code> is incremented by the
  232. * length of <code>s</code>.
  233. *
  234. * @param s a string of bytes to be written.
  235. * @exception IOException if an I/O error occurs.
  236. * @see java.io.FilterOutputStream#out
  237. */
  238. public final void writeBytes(String s) throws IOException {
  239. int len = s.length();
  240. for (int i = 0 ; i < len ; i++) {
  241. out.write((byte)s.charAt(i));
  242. }
  243. incCount(len);
  244. }
  245. /**
  246. * Writes a string to the underlying output stream as a sequence of
  247. * characters. Each character is written to the data output stream as
  248. * if by the <code>writeChar</code> method. If no exception is
  249. * thrown, the counter <code>written</code> is incremented by twice
  250. * the length of <code>s</code>.
  251. *
  252. * @param s a <code>String</code> value to be written.
  253. * @exception IOException if an I/O error occurs.
  254. * @see java.io.DataOutputStream#writeChar(int)
  255. * @see java.io.FilterOutputStream#out
  256. */
  257. public final void writeChars(String s) throws IOException {
  258. int len = s.length();
  259. for (int i = 0 ; i < len ; i++) {
  260. int v = s.charAt(i);
  261. out.write((v >>> 8) & 0xFF);
  262. out.write((v >>> 0) & 0xFF);
  263. }
  264. incCount(len * 2);
  265. }
  266. /**
  267. * Writes a string to the underlying output stream using
  268. * <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
  269. * encoding in a machine-independent manner.
  270. * <p>
  271. * First, two bytes are written to the output stream as if by the
  272. * <code>writeShort</code> method giving the number of bytes to
  273. * follow. This value is the number of bytes actually written out,
  274. * not the length of the string. Following the length, each character
  275. * of the string is output, in sequence, using the modified UTF-8 encoding
  276. * for the character. If no exception is thrown, the counter
  277. * <code>written</code> is incremented by the total number of
  278. * bytes written to the output stream. This will be at least two
  279. * plus the length of <code>str</code>, and at most two plus
  280. * thrice the length of <code>str</code>.
  281. *
  282. * @param str a string to be written.
  283. * @exception IOException if an I/O error occurs.
  284. */
  285. public final void writeUTF(String str) throws IOException {
  286. writeUTF(str, this);
  287. }
  288. /**
  289. * Writes a string to the specified DataOutput using
  290. * <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
  291. * encoding in a machine-independent manner.
  292. * <p>
  293. * First, two bytes are written to out as if by the <code>writeShort</code>
  294. * method giving the number of bytes to follow. This value is the number of
  295. * bytes actually written out, not the length of the string. Following the
  296. * length, each character of the string is output, in sequence, using the
  297. * modified UTF-8 encoding for the character. If no exception is thrown, the
  298. * counter <code>written</code> is incremented by the total number of
  299. * bytes written to the output stream. This will be at least two
  300. * plus the length of <code>str</code>, and at most two plus
  301. * thrice the length of <code>str</code>.
  302. *
  303. * @param str a string to be written.
  304. * @param out destination to write to
  305. * @return The number of bytes written out.
  306. * @exception IOException if an I/O error occurs.
  307. */
  308. static int writeUTF(String str, DataOutput out) throws IOException {
  309. int strlen = str.length();
  310. int utflen = 0;
  311. int c, count = 0;
  312. /* use charAt instead of copying String to char array */
  313. for (int i = 0; i < strlen; i++) {
  314. c = str.charAt(i);
  315. if ((c >= 0x0001) && (c <= 0x007F)) {
  316. utflen++;
  317. } else if (c > 0x07FF) {
  318. utflen += 3;
  319. } else {
  320. utflen += 2;
  321. }
  322. }
  323. if (utflen > 65535)
  324. throw new UTFDataFormatException(
  325. "encoded string too long: " + utflen + " bytes");
  326. byte[] bytearr = null;
  327. if (out instanceof DataOutputStream) {
  328. DataOutputStream dos = (DataOutputStream)out;
  329. if(dos.bytearr == null || (dos.bytearr.length < (utflen+2)))
  330. dos.bytearr = new byte[(utflen*2) + 2];
  331. bytearr = dos.bytearr;
  332. } else {
  333. bytearr = new byte[utflen+2];
  334. }
  335. bytearr[count++] = (byte) ((utflen >>> 8) & 0xFF);
  336. bytearr[count++] = (byte) ((utflen >>> 0) & 0xFF);
  337. int i=0;
  338. for (i=0; i<strlen; i++) {
  339. c = str.charAt(i);
  340. if (!((c >= 0x0001) && (c <= 0x007F))) break;
  341. bytearr[count++] = (byte) c;
  342. }
  343. for (;i < strlen; i++){
  344. c = str.charAt(i);
  345. if ((c >= 0x0001) && (c <= 0x007F)) {
  346. bytearr[count++] = (byte) c;
  347. } else if (c > 0x07FF) {
  348. bytearr[count++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
  349. bytearr[count++] = (byte) (0x80 | ((c >> 6) & 0x3F));
  350. bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));
  351. } else {
  352. bytearr[count++] = (byte) (0xC0 | ((c >> 6) & 0x1F));
  353. bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));
  354. }
  355. }
  356. out.write(bytearr, 0, utflen+2);
  357. return utflen + 2;
  358. }
  359. /**
  360. * Returns the current value of the counter <code>written</code>,
  361. * the number of bytes written to this data output stream so far.
  362. * If the counter overflows, it will be wrapped to Integer.MAX_VALUE.
  363. *
  364. * @return the value of the <code>written</code> field.
  365. * @see java.io.DataOutputStream#written
  366. */
  367. public final int size() {
  368. return written;
  369. }
  370. }