001    /* DataOutputStream.java -- Writes primitive Java datatypes to streams
002       Copyright (C) 1998, 2001, 2003, 2005  Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010     
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package java.io;
040    
041    /* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
042     * "The Java Language Specification", ISBN 0-201-63451-1
043     * Status:  Complete to version 1.1.
044     */
045    
046    /**
047     * This class provides a mechanism for writing primitive Java datatypes
048     * to an <code>OutputStream</code> in a portable way.  Data written to
049     * a stream using this class can be read back in using the
050     * <code>DataInputStream</code> class on any platform.
051     *
052     * @see DataInputStream
053     *
054     * @author Aaron M. Renn (arenn@urbanophile.com)
055     * @author Tom Tromey (tromey@cygnus.com)
056     */
057    public class DataOutputStream extends FilterOutputStream implements DataOutput
058    {
059      /**
060       * This is the total number of bytes that have been written to the
061       * stream by this object instance.
062       */
063      protected int written;
064    
065      /**
066       * Utf8 byte buffer, used by writeUTF()
067       */
068      private byte[] buf;
069      
070      /**
071       * This method initializes an instance of <code>DataOutputStream</code> to
072       * write its data to the specified underlying <code>OutputStream</code>
073       *
074       * @param out The subordinate <code>OutputStream</code> to which this 
075       * object will write
076       */
077      public DataOutputStream (OutputStream out)
078      {
079        super (out);
080        written = 0;
081      }
082    
083      /**
084       * This method flushes any unwritten bytes to the underlying stream.
085       *
086       * @exception IOException If an error occurs.
087       */
088      public void flush () throws IOException
089      {
090        out.flush();
091      }
092    
093      /**
094       * This method returns the total number of bytes that have been written to
095       * the underlying output stream so far.  This is the value of the
096       * <code>written</code> instance variable
097       *
098       * @return The number of bytes written to the stream.
099       */
100      public final int size ()
101      {
102        return written;
103      }
104    
105      /**
106       * This method writes the specified byte (passed as an <code>int</code>)
107       * to the underlying output stream.
108       *
109       * @param value The <code>byte</code> to write, passed as an <code>int</code>.
110       *
111       * @exception IOException If an error occurs.
112       */
113      public synchronized void write (int value) throws IOException
114      {
115        out.write (value);
116        ++written;
117      }
118    
119      /**
120       * This method writes <code>len</code> bytes from the specified byte array
121       * <code>buf</code> starting at position <code>offset</code> into the
122       * buffer to the underlying output stream.
123       *
124       * @param buf The byte array to write from.
125       * @param offset The index into the byte array to start writing from.
126       * @param len The number of bytes to write.
127       *
128       * @exception IOException If an error occurs.
129       */
130      public synchronized void write (byte[] buf, int offset, int len) 
131         throws IOException
132      {
133        out.write(buf, offset, len);
134        written += len;
135      }
136    
137      /**
138       * This method writes a Java boolean value to an output stream.  If
139       * <code>value</code> is <code>true</code>, a byte with the value of
140       * 1 will be written, otherwise a byte with the value of 0 will be
141       * written.
142       *
143       * The value written can be read using the <code>readBoolean</code>
144       * method in <code>DataInput</code>.
145       *
146       * @param value The <code>boolean</code> value to write to the stream
147       *
148       * @exception IOException If an error occurs
149       *
150       * @see DataInput#readBoolean
151       */
152      public final void writeBoolean (boolean value) throws IOException
153      {
154        write (value ? 1 : 0);
155      }
156    
157      /**
158       * This method writes a Java byte value to an output stream.  The
159       * byte to be written will be in the lowest 8 bits of the
160       * <code>int</code> value passed.
161       *
162       * The value written can be read using the <code>readByte</code> or
163       * <code>readUnsignedByte</code> methods in <code>DataInput</code>.
164       *
165       * @param value The <code>byte</code> to write to the stream, passed as 
166       * the low eight bits of an <code>int</code>.
167       *
168       * @exception IOException If an error occurs
169       *
170       * @see DataInput#readByte
171       * @see DataInput#readUnsignedByte
172       */
173      public final void writeByte (int value) throws IOException
174      {
175        write (value & 0xff);
176      }
177    
178      /**
179       * This method writes a Java short value to an output stream.  The
180       * char to be written will be in the lowest 16 bits of the <code>int</code>
181       * value passed.  These bytes will be written "big endian".  That is,
182       * with the high byte written first in the following manner:
183       * <p>
184       * <code>byte0 = (byte)((value & 0xFF00) >> 8);<br>
185       * byte1 = (byte)(value & 0x00FF);</code>
186       * <p>
187       *
188       * The value written can be read using the <code>readShort</code> and
189       * <code>readUnsignedShort</code> methods in <code>DataInput</code>.
190       *
191       * @param value The <code>short</code> value to write to the stream,
192       * passed as an <code>int</code>.
193       *
194       * @exception IOException If an error occurs
195       *
196       * @see DataInput#readShort
197       * @see DataInput#readUnsignedShort
198       */
199      public final synchronized void writeShort (int value) throws IOException
200      {
201        write ((byte) (0xff & (value >> 8)));
202        write ((byte) (0xff & value));
203      }
204    
205      /**
206       * This method writes a Java char value to an output stream.  The
207       * char to be written will be in the lowest 16 bits of the <code>int</code>
208       * value passed.  These bytes will be written "big endian".  That is,
209       * with the high byte written first in the following manner:
210       * <p>
211       * <code>byte0 = (byte)((value & 0xFF00) >> 8);<br>
212       * byte1 = (byte)(value & 0x00FF);</code>
213       * <p>
214       *
215       * The value written can be read using the <code>readChar</code>
216       * method in <code>DataInput</code>.
217       *
218       * @param value The <code>char</code> value to write, 
219       * passed as an <code>int</code>.
220       *
221       * @exception IOException If an error occurs
222       *
223       * @see DataInput#readChar
224       */
225      public final synchronized void writeChar (int value) throws IOException
226      {
227        write ((byte) (0xff & (value >> 8)));
228        write ((byte) (0xff & value));
229      }
230    
231      /**
232       * This method writes a Java int value to an output stream.  The 4 bytes
233       * of the passed value will be written "big endian".  That is, with
234       * the high byte written first in the following manner:
235       * <p>
236       * <code>byte0 = (byte)((value & 0xFF000000) >> 24);<br>
237       * byte1 = (byte)((value & 0x00FF0000) >> 16);<br>
238       * byte2 = (byte)((value & 0x0000FF00) >> 8);<br>
239       * byte3 = (byte)(value & 0x000000FF);</code>
240       * <p>
241       *
242       * The value written can be read using the <code>readInt</code>
243       * method in <code>DataInput</code>.
244       *
245       * @param value The <code>int</code> value to write to the stream
246       *
247       * @exception IOException If an error occurs
248       *
249       * @see DataInput#readInt
250       */
251      public final synchronized void writeInt (int value) throws IOException
252      {
253        write ((byte) (0xff & (value >> 24)));
254        write ((byte) (0xff & (value >> 16)));
255        write ((byte) (0xff & (value >>  8)));
256        write ((byte) (0xff & value));
257      }
258    
259      /**
260       * This method writes a Java long value to an output stream.  The 8 bytes
261       * of the passed value will be written "big endian".  That is, with
262       * the high byte written first in the following manner:
263       * <p>
264       * <code>byte0 = (byte)((value & 0xFF00000000000000L) >> 56);<br>
265       * byte1 = (byte)((value & 0x00FF000000000000L) >> 48);<br>
266       * byte2 = (byte)((value & 0x0000FF0000000000L) >> 40);<br>
267       * byte3 = (byte)((value & 0x000000FF00000000L) >> 32);<br>
268       * byte4 = (byte)((value & 0x00000000FF000000L) >> 24);<br>
269       * byte5 = (byte)((value & 0x0000000000FF0000L) >> 16);<br>
270       * byte6 = (byte)((value & 0x000000000000FF00L) >> 8);<br>
271       * byte7 = (byte)(value & 0x00000000000000FFL);</code>
272       * <p>
273       *
274       * The value written can be read using the <code>readLong</code>
275       * method in <code>DataInput</code>.
276       *
277       * @param value The <code>long</code> value to write to the stream
278       *
279       * @exception IOException If an error occurs
280       *
281       * @see DataInput#readLong
282       */
283      public final synchronized void writeLong (long value) throws IOException
284      {
285        write ((byte) (0xff & (value >> 56)));
286        write ((byte) (0xff & (value>> 48)));
287        write ((byte) (0xff & (value>> 40)));
288        write ((byte) (0xff & (value>> 32)));
289        write ((byte) (0xff & (value>> 24)));
290        write ((byte) (0xff & (value>> 16)));
291        write ((byte) (0xff & (value>>  8)));
292        write ((byte) (0xff & value));
293      }
294    
295      /**
296       * This method writes a Java <code>float</code> value to the stream.  This
297       * value is written by first calling the method
298       * <code>Float.floatToIntBits</code>
299       * to retrieve an <code>int</code> representing the floating point number,
300       * then writing this <code>int</code> value to the stream exactly the same
301       * as the <code>writeInt()</code> method does.
302       *
303       * The value written can be read using the <code>readFloat</code>
304       * method in <code>DataInput</code>.
305       *
306       * @param value The <code>float</code> value to write to the stream
307       *
308       * @exception IOException If an error occurs
309       *
310       * @see #writeInt(int)
311       * @see DataInput#readFloat
312       * @see Float#floatToIntBits
313       */
314      public final void writeFloat (float value) throws IOException
315      {
316        writeInt (Float.floatToIntBits (value));
317      }
318    
319      /**
320       * This method writes a Java <code>double</code> value to the stream.  This
321       * value is written by first calling the method
322       * <code>Double.doubleToLongBits</code>
323       * to retrieve an <code>long</code> representing the floating point number,
324       * then writing this <code>long</code> value to the stream exactly the same
325       * as the <code>writeLong()</code> method does.
326       *
327       * The value written can be read using the <code>readDouble</code>
328       * method in <code>DataInput</code>.
329       *
330       * @param value The <code>double</code> value to write to the stream
331       *
332       * @exception IOException If an error occurs
333       *
334       * @see #writeLong(long)
335       * @see DataInput#readDouble
336       * @see Double#doubleToLongBits
337       */
338      public final void writeDouble (double value) throws IOException
339      {
340        writeLong (Double.doubleToLongBits (value));
341      }
342    
343      /**
344       * This method writes all the bytes in a <code>String</code> out to the
345       * stream.  One byte is written for each character in the
346       * <code>String</code>.
347       * The high eight bits of each character are discarded, thus this
348       * method is inappropriate for completely representing Unicode characters.
349       *
350       * @param value The <code>String</code> to write to the stream
351       *
352       * @exception IOException If an error occurs
353       */
354      public final void writeBytes (String value) throws IOException
355      {
356        int len = value.length();
357        for (int i = 0; i < len; ++i)
358          writeByte (value.charAt(i));
359      }
360    
361      /**
362       * This method writes all the characters of a <code>String</code> to an
363       * output stream as an array of <code>char</code>'s. Each character
364       * is written using the method specified in the <code>writeChar</code>
365       * method.
366       *
367       * @param value The <code>String</code> to write to the stream
368       *
369       * @exception IOException If an error occurs
370       *
371       * @see #writeChar(char)
372       */
373      public final void writeChars (String value) throws IOException
374      {
375        int len = value.length();
376        for (int i = 0; i < len; ++i)
377          writeChar (value.charAt(i));
378      }
379    
380      /**
381       *  Calculate the length, in bytes, of a <code>String</code> in Utf8 format.
382       *
383       *  @param value The <code>String</code> to measure
384       *  @param start String index at which to begin count
385       *  @param sum Starting Utf8 byte count
386       *
387       *  @throws UTFDataFormatException if result would exceed 65535
388       */
389      private int getUTFlength(String value, int start, int sum)
390        throws IOException
391      {
392        int len = value.length();
393    
394        for (int i = start; i < len && sum <= 65535; ++i)
395          {
396            char c = value.charAt(i);
397            if (c >= '\u0001' && c <= '\u007f')
398              sum += 1;
399            else if (c == '\u0000' || (c >= '\u0080' && c <= '\u07ff'))
400              sum += 2;
401            else
402              sum += 3;
403          }
404    
405        if (sum > 65535)
406          throw new UTFDataFormatException ();
407    
408        return sum;
409      }
410      
411      /**
412       * This method writes a Java <code>String</code> to the stream in a modified
413       * UTF-8 format.  First, two bytes are written to the stream indicating the
414       * number of bytes to follow.  Note that this is the number of bytes in the
415       * encoded <code>String</code> not the <code>String</code> length.  Next
416       * come the encoded characters.  Each character in the <code>String</code>
417       * is encoded as either one, two or three bytes.  For characters in the
418       * range of <code>\u0001</code> to <\u007F>, one byte is used.  The character
419       * value goes into bits 0-7 and bit eight is 0.  For characters in the range
420       * of <code>\u0080</code> to <code>\u007FF</code>, two bytes are used.  Bits
421       * 6-10 of the character value are encoded bits 0-4 of the first byte, with
422       * the high bytes having a value of "110".  Bits 0-5 of the character value
423       * are stored in bits 0-5 of the second byte, with the high bits set to
424       * "10".  This type of encoding is also done for the null character
425       * <code>\u0000</code>.  This eliminates any C style NUL character values
426       * in the output.  All remaining characters are stored as three bytes.
427       * Bits 12-15 of the character value are stored in bits 0-3 of the first
428       * byte.  The high bits of the first bytes are set to "1110".  Bits 6-11
429       * of the character value are stored in bits 0-5 of the second byte.  The
430       * high bits of the second byte are set to "10".  And bits 0-5 of the
431       * character value are stored in bits 0-5 of byte three, with the high bits
432       * of that byte set to "10".
433       *
434       * The value written can be read using the <code>readUTF</code>
435       * method in <code>DataInput</code>.
436       *
437       * @param value The <code>String</code> to write to the output in UTF format
438       *
439       * @exception IOException If an error occurs
440       *
441       * @see DataInput#readUTF
442       */
443      public final synchronized void writeUTF(String value) throws IOException
444      {
445        int len = value.length();
446        int i = 0;
447        int pos = 0;
448        boolean lengthWritten = false;
449    
450        if (buf == null)
451          buf = new byte[512];
452        
453        do
454          {
455            while (i < len && pos < buf.length - 3)
456              {
457                char c = value.charAt(i++);
458                if (c >= '\u0001' && c <= '\u007f')
459                  buf[pos++] = (byte) c;
460                else if (c == '\u0000' || (c >= '\u0080' && c <= '\u07ff'))
461                  {
462                    buf[pos++] = (byte) (0xc0 | (0x1f & (c >> 6)));
463                    buf[pos++] = (byte) (0x80 | (0x3f & c));
464                  }
465                else
466                  {
467                    // JSL says the first byte should be or'd with 0xc0, but
468                    // that is a typo.  Unicode says 0xe0, and that is what is
469                    // consistent with DataInputStream.
470                    buf[pos++] = (byte) (0xe0 | (0x0f & (c >> 12)));
471                    buf[pos++] = (byte) (0x80 | (0x3f & (c >> 6)));
472                    buf[pos++] = (byte) (0x80 | (0x3f & c));
473                  }
474              }
475            if (! lengthWritten)
476              {
477                if (i == len)
478                  writeShort(pos);
479                else
480                  writeShort(getUTFlength(value, i, pos));
481                lengthWritten = true;
482              }
483            write(buf, 0, pos);
484            pos = 0;
485         }
486        while (i < len);
487      }
488    
489    } // class DataOutputStream
490