Frames | No Frames |
1: /* DataOutputStream.java -- Writes primitive Java datatypes to streams 2: Copyright (C) 1998, 2001, 2003, 2005, 2008 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package java.io; 40: 41: /* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 42: * "The Java Language Specification", ISBN 0-201-63451-1 43: * Status: Complete to version 1.1. 44: */ 45: 46: /** 47: * This class provides a mechanism for writing primitive Java datatypes 48: * to an <code>OutputStream</code> in a portable way. Data written to 49: * a stream using this class can be read back in using the 50: * <code>DataInputStream</code> class on any platform. 51: * 52: * @see DataInputStream 53: * 54: * @author Aaron M. Renn (arenn@urbanophile.com) 55: * @author Tom Tromey (tromey@cygnus.com) 56: */ 57: public class DataOutputStream extends FilterOutputStream implements DataOutput 58: { 59: /** 60: * This is the total number of bytes that have been written to the 61: * stream by this object instance. 62: */ 63: protected int written; 64: 65: /** 66: * Utf8 byte buffer, used by writeUTF() 67: */ 68: private byte[] buf; 69: 70: /** 71: * This method initializes an instance of <code>DataOutputStream</code> to 72: * write its data to the specified underlying <code>OutputStream</code> 73: * 74: * @param out The subordinate <code>OutputStream</code> to which this 75: * object will write 76: */ 77: public DataOutputStream (OutputStream out) 78: { 79: super (out); 80: written = 0; 81: } 82: 83: /** 84: * This method flushes any unwritten bytes to the underlying stream. 85: * 86: * @exception IOException If an error occurs. 87: */ 88: public void flush () throws IOException 89: { 90: out.flush(); 91: } 92: 93: /** 94: * This method returns the total number of bytes that have been written to 95: * the underlying output stream so far. This is the value of the 96: * <code>written</code> instance variable 97: * 98: * @return The number of bytes written to the stream. 99: */ 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: * This method is package-private so that <code>ObjectOutputStream</code> 383: * may use it. The return type is long so that a long string whose 384: * Utf8 byte count is 64 bit long may be handled. 385: * 386: * @param value The <code>String</code> to measure 387: * @param start String index at which to begin count 388: * @param sum Starting Utf8 byte count 389: * 390: */ 391: long getUTFlength(String value, int start, long sum) 392: { 393: int len = value.length(); 394: 395: for (int i = start; i < len; ++i) 396: { 397: char c = value.charAt(i); 398: if (c >= '\u0001' && c <= '\u007f') 399: sum += 1; 400: else if (c == '\u0000' || (c >= '\u0080' && c <= '\u07ff')) 401: sum += 2; 402: else 403: sum += 3; 404: } 405: 406: return sum; 407: } 408: 409: /** 410: * This method writes a Java <code>String</code> to the stream in a modified 411: * UTF-8 format. First, two bytes are written to the stream indicating the 412: * number of bytes to follow. Note that this is the number of bytes in the 413: * encoded <code>String</code> not the <code>String</code> length. Next 414: * come the encoded characters. Each character in the <code>String</code> 415: * is encoded as either one, two or three bytes. For characters in the 416: * range of <code>\u0001</code> to <\u007F>, one byte is used. The character 417: * value goes into bits 0-7 and bit eight is 0. For characters in the range 418: * of <code>\u0080</code> to <code>\u007FF</code>, two bytes are used. Bits 419: * 6-10 of the character value are encoded bits 0-4 of the first byte, with 420: * the high bytes having a value of "110". Bits 0-5 of the character value 421: * are stored in bits 0-5 of the second byte, with the high bits set to 422: * "10". This type of encoding is also done for the null character 423: * <code>\u0000</code>. This eliminates any C style NUL character values 424: * in the output. All remaining characters are stored as three bytes. 425: * Bits 12-15 of the character value are stored in bits 0-3 of the first 426: * byte. The high bits of the first bytes are set to "1110". Bits 6-11 427: * of the character value are stored in bits 0-5 of the second byte. The 428: * high bits of the second byte are set to "10". And bits 0-5 of the 429: * character value are stored in bits 0-5 of byte three, with the high bits 430: * of that byte set to "10". 431: * 432: * The value written can be read using the <code>readUTF</code> 433: * method in <code>DataInput</code>. 434: * 435: * @param value The <code>String</code> to write to the output in UTF format 436: * 437: * @exception IOException If an error occurs 438: * 439: * @see DataInput#readUTF 440: */ 441: public final synchronized void writeUTF(String value) throws IOException 442: { 443: long l = getUTFlength(value, 0, 0); 444: if (l > 65535) 445: throw new UTFDataFormatException (); 446: writeUTFShort(value, (int)l); 447: } 448: 449: /** 450: * This method performs the main task of <code>writeUTF</code>. 451: * This method is package-private because ObjectOutputStream uses it. 452: * 453: * @param value The <code>String</code> to write to the output in UTF format 454: * 455: * @param bytelen The UTF-8 byte length of the <code>String</code>. When 456: * this method is called, the expected byte length must have been calculated 457: * by <code>getUTFlength</code>. 458: * 459: * @exception IOException If an error occurs 460: * 461: * @see DataInput#readUTF 462: */ 463: final synchronized void writeUTFShort(String value, int bytelen) 464: throws IOException 465: { 466: writeShort(bytelen); 467: writeUTFBytes(value); 468: } 469: 470: /** 471: * This method is similar to <code>writeUTF</code>, but it writes the 472: * UTF-8 byte length in 64 bits. 473: * This method is not public but <code>ObjectOutputStream</code> uses it. 474: * 475: * @param value The <code>String</code> to write to the output in UTF format 476: * 477: * @param bytelen The UTF-8 byte length of the <code>String</code>. When 478: * this method is called, the expected byte length must have been calculated 479: * by <code>getUTFlength</code>. 480: * 481: * @exception IOException If an error occurs 482: * 483: */ 484: final synchronized void writeUTFLong(String value, long bytelen) 485: throws IOException 486: { 487: writeLong(bytelen); 488: writeUTFBytes(value); 489: } 490: 491: /** 492: * This method performes the main task of <code>writeUTF</code> and 493: * <code>WriteUTFLong</code>, which is to write the UTF-8 byte 494: * sequence to the output. 495: * 496: * @param value The <code>String</code> to write to the output in UTF format 497: * 498: * @exception IOException If an error occurs 499: * 500: */ 501: private final synchronized void writeUTFBytes(String value) 502: throws IOException 503: { 504: int len = value.length(); 505: int i = 0; 506: int pos = 0; 507: 508: if (buf == null) 509: buf = new byte[512]; 510: 511: do 512: { 513: while (i < len && pos < buf.length - 3) 514: { 515: char c = value.charAt(i++); 516: if (c >= '\u0001' && c <= '\u007f') 517: buf[pos++] = (byte) c; 518: else if (c == '\u0000' || (c >= '\u0080' && c <= '\u07ff')) 519: { 520: buf[pos++] = (byte) (0xc0 | (0x1f & (c >> 6))); 521: buf[pos++] = (byte) (0x80 | (0x3f & c)); 522: } 523: else 524: { 525: // JSL says the first byte should be or'd with 0xc0, but 526: // that is a typo. Unicode says 0xe0, and that is what is 527: // consistent with DataInputStream. 528: buf[pos++] = (byte) (0xe0 | (0x0f & (c >> 12))); 529: buf[pos++] = (byte) (0x80 | (0x3f & (c >> 6))); 530: buf[pos++] = (byte) (0x80 | (0x3f & c)); 531: } 532: } 533: write(buf, 0, pos); 534: pos = 0; 535: } 536: while (i < len); 537: } 538: 539: } // class DataOutputStream