1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package java.io; 19 20 /** 21 * Wraps an existing {@link OutputStream} and writes typed data to it. 22 * Typically, this stream can be read in by DataInputStream. Types that can be 23 * written include byte, 16-bit short, 32-bit int, 32-bit float, 64-bit long, 24 * 64-bit double, byte strings, and {@link DataInput MUTF-8} encoded strings. 25 * 26 * @see DataInputStream 27 */ 28 public class DataOutputStream extends FilterOutputStream implements DataOutput { 29 30 /** 31 * The number of bytes written out so far. 32 */ 33 protected int written; 34 byte[] buff; 35 36 /** 37 * Constructs a new {@code DataOutputStream} on the {@code OutputStream} 38 * {@code out}. Note that data written by this stream is not in a human 39 * readable form but can be reconstructed by using a {@link DataInputStream} 40 * on the resulting output. 41 * 42 * @param out 43 * the target stream for writing. 44 */ 45 public DataOutputStream(OutputStream out) { 46 super(out); 47 buff = new byte[8]; 48 } 49 50 /** 51 * Flushes this stream to ensure all pending data is sent out to the target 52 * stream. This implementation then also flushes the target stream. 53 * 54 * @throws IOException 55 * if an error occurs attempting to flush this stream. 56 */ 57 @Override 58 public void flush() throws IOException { 59 super.flush(); 60 } 61 62 /** 63 * Returns the total number of bytes written to the target stream so far. 64 * 65 * @return the number of bytes written to the target stream. 66 */ 67 public final int size() { 68 if (written < 0) { 69 written = Integer.MAX_VALUE; 70 } 71 return written; 72 } 73 74 /** 75 * Writes {@code count} bytes from the byte array {@code buffer} starting at 76 * {@code offset} to the target stream. 77 * 78 * @param buffer 79 * the buffer to write to the target stream. 80 * @param offset 81 * the index of the first byte in {@code buffer} to write. 82 * @param count 83 * the number of bytes from the {@code buffer} to write. 84 * @throws IOException 85 * if an error occurs while writing to the target stream. 86 * @throws NullPointerException 87 * if {@code buffer} is {@code null}. 88 * @see DataInputStream#readFully(byte[]) 89 * @see DataInputStream#readFully(byte[], int, int) 90 */ 91 @Override 92 public void write(byte[] buffer, int offset, int count) throws IOException { 93 // BEGIN android-note 94 // changed array notation to be consistent with the rest of harmony 95 // END android-note 96 if (buffer == null) { 97 throw new NullPointerException("buffer == null"); 98 } 99 out.write(buffer, offset, count); 100 written += count; 101 } 102 103 /** 104 * Writes a byte to the target stream. Only the least significant byte of 105 * the integer {@code oneByte} is written. 106 * 107 * @param oneByte 108 * the byte to write to the target stream. 109 * @throws IOException 110 * if an error occurs while writing to the target stream. 111 * @see DataInputStream#readByte() 112 */ 113 @Override 114 public void write(int oneByte) throws IOException { 115 out.write(oneByte); 116 written++; 117 } 118 119 /** 120 * Writes a boolean to the target stream. 121 * 122 * @param val 123 * the boolean value to write to the target stream. 124 * @throws IOException 125 * if an error occurs while writing to the target stream. 126 * @see DataInputStream#readBoolean() 127 */ 128 public final void writeBoolean(boolean val) throws IOException { 129 out.write(val ? 1 : 0); 130 written++; 131 } 132 133 /** 134 * Writes an 8-bit byte to the target stream. Only the least significant 135 * byte of the integer {@code val} is written. 136 * 137 * @param val 138 * the byte value to write to the target stream. 139 * @throws IOException 140 * if an error occurs while writing to the target stream. 141 * @see DataInputStream#readByte() 142 * @see DataInputStream#readUnsignedByte() 143 */ 144 public final void writeByte(int val) throws IOException { 145 out.write(val); 146 written++; 147 } 148 149 /** 150 * Writes the low order bytes from a string to the target stream. 151 * 152 * @param str 153 * the string containing the bytes to write to the target stream. 154 * @throws IOException 155 * if an error occurs while writing to the target stream. 156 * @see DataInputStream#readFully(byte[]) 157 * @see DataInputStream#readFully(byte[],int,int) 158 */ 159 public final void writeBytes(String str) throws IOException { 160 if (str.length() == 0) { 161 return; 162 } 163 byte[] bytes = new byte[str.length()]; 164 for (int index = 0; index < str.length(); index++) { 165 bytes[index] = (byte) str.charAt(index); 166 } 167 out.write(bytes); 168 written += bytes.length; 169 } 170 171 /** 172 * Writes a 16-bit character to the target stream. Only the two lower bytes 173 * of the integer {@code val} are written, with the higher one written 174 * first. This corresponds to the Unicode value of {@code val}. 175 * 176 * @param val 177 * the character to write to the target stream 178 * @throws IOException 179 * if an error occurs while writing to the target stream. 180 * @see DataInputStream#readChar() 181 */ 182 public final void writeChar(int val) throws IOException { 183 buff[0] = (byte) (val >> 8); 184 buff[1] = (byte) val; 185 out.write(buff, 0, 2); 186 written += 2; 187 } 188 189 /** 190 * Writes the 16-bit characters contained in {@code str} to the target 191 * stream. 192 * 193 * @param str 194 * the string that contains the characters to write to this 195 * stream. 196 * @throws IOException 197 * if an error occurs while writing to the target stream. 198 * @see DataInputStream#readChar() 199 */ 200 public final void writeChars(String str) throws IOException { 201 byte[] newBytes = new byte[str.length() * 2]; 202 for (int index = 0; index < str.length(); index++) { 203 int newIndex = index == 0 ? index : index * 2; 204 newBytes[newIndex] = (byte) (str.charAt(index) >> 8); 205 newBytes[newIndex + 1] = (byte) str.charAt(index); 206 } 207 out.write(newBytes); 208 written += newBytes.length; 209 } 210 211 /** 212 * Writes a 64-bit double to the target stream. The resulting output is the 213 * eight bytes resulting from calling Double.doubleToLongBits(). 214 * 215 * @param val 216 * the double to write to the target stream. 217 * @throws IOException 218 * if an error occurs while writing to the target stream. 219 * @see DataInputStream#readDouble() 220 */ 221 public final void writeDouble(double val) throws IOException { 222 writeLong(Double.doubleToLongBits(val)); 223 } 224 225 /** 226 * Writes a 32-bit float to the target stream. The resulting output is the 227 * four bytes resulting from calling Float.floatToIntBits(). 228 * 229 * @param val 230 * the float to write to the target stream. 231 * @throws IOException 232 * if an error occurs while writing to the target stream. 233 * @see DataInputStream#readFloat() 234 */ 235 public final void writeFloat(float val) throws IOException { 236 writeInt(Float.floatToIntBits(val)); 237 } 238 239 /** 240 * Writes a 32-bit int to the target stream. The resulting output is the 241 * four bytes, highest order first, of {@code val}. 242 * 243 * @param val 244 * the int to write to the target stream. 245 * @throws IOException 246 * if an error occurs while writing to the target stream. 247 * @see DataInputStream#readInt() 248 */ 249 public final void writeInt(int val) throws IOException { 250 buff[0] = (byte) (val >> 24); 251 buff[1] = (byte) (val >> 16); 252 buff[2] = (byte) (val >> 8); 253 buff[3] = (byte) val; 254 out.write(buff, 0, 4); 255 written += 4; 256 } 257 258 /** 259 * Writes a 64-bit long to the target stream. The resulting output is the 260 * eight bytes, highest order first, of {@code val}. 261 * 262 * @param val 263 * the long to write to the target stream. 264 * @throws IOException 265 * if an error occurs while writing to the target stream. 266 * @see DataInputStream#readLong() 267 */ 268 public final void writeLong(long val) throws IOException { 269 buff[0] = (byte) (val >> 56); 270 buff[1] = (byte) (val >> 48); 271 buff[2] = (byte) (val >> 40); 272 buff[3] = (byte) (val >> 32); 273 buff[4] = (byte) (val >> 24); 274 buff[5] = (byte) (val >> 16); 275 buff[6] = (byte) (val >> 8); 276 buff[7] = (byte) val; 277 out.write(buff, 0, 8); 278 written += 8; 279 } 280 281 int writeLongToBuffer(long val, 282 byte[] buffer, int offset) throws IOException { 283 buffer[offset++] = (byte) (val >> 56); 284 buffer[offset++] = (byte) (val >> 48); 285 buffer[offset++] = (byte) (val >> 40); 286 buffer[offset++] = (byte) (val >> 32); 287 buffer[offset++] = (byte) (val >> 24); 288 buffer[offset++] = (byte) (val >> 16); 289 buffer[offset++] = (byte) (val >> 8); 290 buffer[offset++] = (byte) val; 291 return offset; 292 } 293 294 /** 295 * Writes the specified 16-bit short to the target stream. Only the lower 296 * two bytes of the integer {@code val} are written, with the higher one 297 * written first. 298 * 299 * @param val 300 * the short to write to the target stream. 301 * @throws IOException 302 * if an error occurs while writing to the target stream. 303 * @see DataInputStream#readShort() 304 * @see DataInputStream#readUnsignedShort() 305 */ 306 public final void writeShort(int val) throws IOException { 307 buff[0] = (byte) (val >> 8); 308 buff[1] = (byte) val; 309 out.write(buff, 0, 2); 310 written += 2; 311 } 312 313 int writeShortToBuffer(int val, 314 byte[] buffer, int offset) throws IOException { 315 buffer[offset++] = (byte) (val >> 8); 316 buffer[offset++] = (byte) val; 317 return offset; 318 } 319 320 /** 321 * Writes the specified encoded in {@link DataInput modified UTF-8} to this 322 * stream. 323 * 324 * @param str 325 * the string to write to the target stream encoded in 326 * {@link DataInput modified UTF-8}. 327 * @throws IOException 328 * if an error occurs while writing to the target stream. 329 * @throws UTFDataFormatException 330 * if the encoded string is longer than 65535 bytes. 331 * @see DataInputStream#readUTF() 332 */ 333 public final void writeUTF(String str) throws IOException { 334 long utfCount = countUTFBytes(str); 335 if (utfCount > 65535) { 336 throw new UTFDataFormatException("String more than 65535 UTF bytes long"); 337 } 338 byte[] buffer = new byte[(int)utfCount + 2]; 339 int offset = 0; 340 offset = writeShortToBuffer((int) utfCount, buffer, offset); 341 // BEGIN android-changed 342 // removed unused parameter count 343 offset = writeUTFBytesToBuffer(str, buffer, offset); 344 // BEGIN android-changed 345 write(buffer, 0, offset); 346 } 347 348 long countUTFBytes(String str) { 349 int utfCount = 0, length = str.length(); 350 for (int i = 0; i < length; i++) { 351 int charValue = str.charAt(i); 352 if (charValue > 0 && charValue <= 127) { 353 utfCount++; 354 } else if (charValue <= 2047) { 355 utfCount += 2; 356 } else { 357 utfCount += 3; 358 } 359 } 360 return utfCount; 361 } 362 363 int writeUTFBytesToBuffer(String str, 364 byte[] buffer, int offset) throws IOException { 365 // BEGIN android-note 366 // removed unused parameter count 367 // END android-note 368 int length = str.length(); 369 for (int i = 0; i < length; i++) { 370 int charValue = str.charAt(i); 371 if (charValue > 0 && charValue <= 127) { 372 buffer[offset++] = (byte) charValue; 373 } else if (charValue <= 2047) { 374 buffer[offset++] = (byte) (0xc0 | (0x1f & (charValue >> 6))); 375 buffer[offset++] = (byte) (0x80 | (0x3f & charValue)); 376 } else { 377 buffer[offset++] = (byte) (0xe0 | (0x0f & (charValue >> 12))); 378 buffer[offset++] = (byte) (0x80 | (0x3f & (charValue >> 6))); 379 buffer[offset++] = (byte) (0x80 | (0x3f & charValue)); 380 } 381 } 382 return offset; 383 } 384 } 385