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