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