Home | History | Annotate | Download | only in io
      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      */
     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      */
     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      */
     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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    413     public final int size() {
    414         return written;
    415     }
    416 }
    417