1 //****************************************************************************** 2 // 3 // File: DataOutputStream.java 4 // Package: edu.rit.io 5 // Unit: Class edu.rit.io.DataOutputStream 6 // 7 // This Java source file is copyright (C) 2009 by Alan Kaminsky. All rights 8 // reserved. For further information, contact the author, Alan Kaminsky, at 9 // ark@cs.rit.edu. 10 // 11 // This Java source file is part of the Parallel Java Library ("PJ"). PJ is free 12 // software; you can redistribute it and/or modify it under the terms of the GNU 13 // General Public License as published by the Free Software Foundation; either 14 // version 3 of the License, or (at your option) any later version. 15 // 16 // PJ is distributed in the hope that it will be useful, but WITHOUT ANY 17 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 18 // A PARTICULAR PURPOSE. See the GNU General Public License for more details. 19 // 20 // Linking this library statically or dynamically with other modules is making a 21 // combined work based on this library. Thus, the terms and conditions of the GNU 22 // General Public License cover the whole combination. 23 // 24 // As a special exception, the copyright holders of this library give you 25 // permission to link this library with independent modules to produce an 26 // executable, regardless of the license terms of these independent modules, and 27 // to copy and distribute the resulting executable under terms of your choice, 28 // provided that you also meet, for each linked independent module, the terms 29 // and conditions of the license of that module. An independent module is a module 30 // which is not derived from or based on this library. If you modify this library, 31 // you may extend this exception to your version of the library, but you are not 32 // obligated to do so. If you do not wish to do so, delete this exception 33 // statement from your version. 34 // 35 // A copy of the GNU General Public License is provided in the file gpl.txt. You 36 // may also obtain a copy of the GNU General Public License on the World Wide 37 // Web at http://www.gnu.org/licenses/gpl.html. 38 // 39 //****************************************************************************** 40 package edu.rit.io; 41 42 import java.io.FilterOutputStream; 43 import java.io.IOException; 44 import java.io.OutputStream; 45 46 /** 47 * Class DataOutputStream provides an output stream that writes primitive data 48 * types and strings in binary form. It behaves similarly to class 49 * java.io.DataOutputStream, except the methods for writing types byte, short, 50 * char, int, long, and String are implemented differently. These methods write 51 * an integer value using a variable number of bytes, as described below. This 52 * can save space in the file if small integer values are written more 53 * frequently than large integer values. The resulting byte stream can be read 54 * using class {@linkplain DataInputStream}. 55 * <p> 56 * Note that class DataOutputStream does <I>not</I> implement interface 57 * java.io.DataOutput, because the methods do not obey the contract specified in 58 * that interface. 59 * 60 * @author Alan Kaminsky 61 * @version 18-Dec-2009 62 */ 63 public class DataOutputStream 64 extends FilterOutputStream { 65 66 // Exported constructors. 67 68 /** 69 * Construct a new data output stream. 70 * 71 * @param out Underlying output stream. 72 */ 73 public DataOutputStream(OutputStream out) { 74 super(out); 75 } 76 77 // Exported operations. 78 79 /** 80 * Write the given Boolean value to this data output stream. One byte is 81 * written, either 0 (if <code>v</code> is false) or 1 (if <code>v</code> is true). 82 * 83 * @param v Boolean value. 84 * @throws java.io.IOException Thrown if an I/O error occurred. 85 * @throws java.io.IOException if any. 86 */ 87 public void writeBoolean(boolean v) 88 throws IOException { 89 out.write(v ? 1 : 0); 90 } 91 92 /** 93 * Write the given integer value to this data output stream. This method can 94 * be used to write values of type byte, short, char, or int. From one to 95 * five bytes are written, in big-endian order, as follows: 96 * <UL> 97 * 98 * <LI> 99 * If −64 ≤ <code>v</code> ≤ 63, then one byte is written, 100 * containing 0 (1 bit) followed by <code>v</code> (7 bits). 101 * 102 * <LI> 103 * Else if −8192 ≤ <code>v</code> ≤ 8191, then two bytes are 104 * written, containing 10 (2 bits) followed by <code>v</code> (14 bits). 105 * 106 * <LI> 107 * Else if −1048576 ≤ <code>v</code> ≤ 1048575, then three bytes are 108 * written, containing 110 (3 bits) followed by <code>v</code> (21 bits). 109 * 110 * <LI> 111 * Else if −134217728 ≤ <code>v</code> ≤ 134217727, then four bytes 112 * are written, containing 1110 (4 bits) followed by <code>v</code> (28 bits). 113 * 114 * <LI> 115 * Else five bytes are written, containing 1111 (4 bits) followed by 116 * <code>v</code> (sign-extended to 36 bits). 117 * </UL> 118 * 119 * @param v Integer value. 120 * @throws java.io.IOException Thrown if an I/O error occurred. 121 * @throws java.io.IOException if any. 122 */ 123 public void writeInt(int v) 124 throws IOException { 125 if (-64 <= v && v <= 63) { 126 out.write(v & 0x7F); 127 } else if (-8192 <= v && v <= 8191) { 128 out.write(((v >> 8) & 0x3F) | 0x80); 129 out.write(v); 130 } else if (-1048576 <= v && v <= 1048575) { 131 out.write(((v >> 16) & 0x1F) | 0xC0); 132 out.write(v >> 8); 133 out.write(v); 134 } else if (-134217728 <= v && v <= 134217727) { 135 out.write(((v >> 24) & 0x0F) | 0xE0); 136 out.write(v >> 16); 137 out.write(v >> 8); 138 out.write(v); 139 } else { 140 out.write(((v >> 32) & 0x0F) | 0xF0); 141 out.write(v >> 24); 142 out.write(v >> 16); 143 out.write(v >> 8); 144 out.write(v); 145 } 146 } 147 148 /** 149 * Write the given unsigned integer value to this data output stream. This 150 * method can be used to write values of type byte, short, char, or int. 151 * From one to five bytes are written, in big-endian order, as follows: 152 * <UL> 153 * 154 * <LI> 155 * If 0 ≤ <code>v</code> ≤ 127, then one byte is written, containing 0 (1 156 * bit) followed by <code>v</code> (7 bits). 157 * 158 * <LI> 159 * Else if 128 ≤ <code>v</code> ≤ 16383, then two bytes are written, 160 * containing 10 (2 bits) followed by <code>v</code> (14 bits). 161 * 162 * <LI> 163 * Else if 16384 ≤ <code>v</code> ≤ 2097151, then three bytes are written, 164 * containing 110 (3 bits) followed by <code>v</code> (21 bits). 165 * 166 * <LI> 167 * Else if 2097152 ≤ <code>v</code> ≤ 268435455, then four bytes are 168 * written, containing 1110 (4 bits) followed by <code>v</code> (28 bits). 169 * 170 * <LI> 171 * Else five bytes are written, containing 1111 (4 bits) followed by 172 * <code>v</code> (zero-extended to 36 bits). 173 * </UL> 174 * 175 * @param v Integer value. 176 * @throws java.io.IOException Thrown if an I/O error occurred. 177 * @throws java.io.IOException if any. 178 */ 179 public void writeUnsignedInt(int v) 180 throws IOException { 181 if (0 <= v && v <= 127) { 182 out.write(v); 183 } else if (128 <= v && v <= 16383) { 184 out.write((v >> 8) | 0x80); 185 out.write(v); 186 } else if (16384 <= v && v <= 2097151) { 187 out.write((v >> 16) | 0xC0); 188 out.write(v >> 8); 189 out.write(v); 190 } else if (2097152 <= v && v <= 268435455) { 191 out.write((v >> 24) | 0xE0); 192 out.write(v >> 16); 193 out.write(v >> 8); 194 out.write(v); 195 } else { 196 out.write(0xF0); 197 out.write(v >> 24); 198 out.write(v >> 16); 199 out.write(v >> 8); 200 out.write(v); 201 } 202 } 203 204 /** 205 * Write the given long value to this data output stream. From one to nine 206 * bytes are written, in big-endian order, as follows: 207 * <UL> 208 * 209 * <LI> 210 * If −64 ≤ <code>v</code> ≤ 63, then one byte is written, 211 * containing 0 (1 bit) followed by <code>v</code> (7 bits). 212 * 213 * <LI> 214 * Else if −8192 ≤ <code>v</code> ≤ 8191, then two bytes are 215 * written, containing 10 (2 bits) followed by <code>v</code> (14 bits). 216 * 217 * <LI> 218 * Else if −1048576 ≤ <code>v</code> ≤ 1048575, then three bytes are 219 * written, containing 110 (3 bits) followed by <code>v</code> (21 bits). 220 * 221 * <LI> 222 * Else if −134217728 ≤ <code>v</code> ≤ 134217727, then four bytes 223 * are written, containing 1110 (4 bits) followed by <code>v</code> (28 bits). 224 * 225 * <LI> 226 * Else if −17179869184 ≤ <code>v</code> ≤ 17179869183, then five 227 * bytes are written, containing 11110 (5 bits) followed by <code>v</code> (35 228 * bits). 229 * 230 * <LI> 231 * Else if −2199023255552 ≤ <code>v</code> ≤ 2199023255551, then six 232 * bytes are written, containing 111110 (6 bits) followed by <code>v</code> (42 233 * bits). 234 * 235 * <LI> 236 * Else if −281474976710656 ≤ <code>v</code> ≤ 281474976710655, then 237 * seven bytes are written, containing 1111110 (7 bits) followed by 238 * <code>v</code> (49 bits). 239 * 240 * <LI> 241 * Else if −36028797018963968 ≤ <code>v</code> ≤ 36028797018963967, 242 * then eight bytes are written, containing 11111110 (8 bits) followed by 243 * <code>v</code> (56 bits). 244 * 245 * <LI> 246 * Else nine bytes are written, containing 11111111 (8 bits) followed by 247 * <code>v</code> (64 bits). 248 * </UL> 249 * 250 * @param v Integer value. 251 * @throws java.io.IOException Thrown if an I/O error occurred. 252 * @throws java.io.IOException if any. 253 */ 254 public void writeLong(long v) 255 throws IOException { 256 if (-64L <= v && v <= 63L) { 257 out.write((int) (v) & 0x7F); 258 } else if (-8192L <= v && v <= 8191L) { 259 out.write(((int) (v >> 8L) & 0x3F) | 0x80); 260 out.write((int) (v)); 261 } else if (-1048576L <= v && v <= 1048575L) { 262 out.write(((int) (v >> 16L) & 0x1F) | 0xC0); 263 out.write((int) (v >> 8L)); 264 out.write((int) (v)); 265 } else if (-134217728L <= v && v <= 134217727L) { 266 out.write(((int) (v >> 24L) & 0x0F) | 0xE0); 267 out.write((int) (v >> 16L)); 268 out.write((int) (v >> 8L)); 269 out.write((int) (v)); 270 } else if (-17179869184L <= v && v <= 17179869183L) { 271 out.write(((int) (v >> 32L) & 0x07) | 0xF0); 272 out.write((int) (v >> 24L)); 273 out.write((int) (v >> 16L)); 274 out.write((int) (v >> 8L)); 275 out.write((int) (v)); 276 } else if (-2199023255552L <= v && v <= 2199023255551L) { 277 out.write(((int) (v >> 40L) & 0x03) | 0xF8); 278 out.write((int) (v >> 32L)); 279 out.write((int) (v >> 24L)); 280 out.write((int) (v >> 16L)); 281 out.write((int) (v >> 8L)); 282 out.write((int) (v)); 283 } else if (-281474976710656L <= v && v <= 281474976710656L) { 284 out.write(((int) (v >> 48L) & 0x01) | 0xFC); 285 out.write((int) (v >> 40L)); 286 out.write((int) (v >> 32L)); 287 out.write((int) (v >> 24L)); 288 out.write((int) (v >> 16L)); 289 out.write((int) (v >> 8L)); 290 out.write((int) (v)); 291 } else if (-36028797018963968L <= v && v <= 36028797018963968L) { 292 out.write(0xFE); 293 out.write((int) (v >> 48L)); 294 out.write((int) (v >> 40L)); 295 out.write((int) (v >> 32L)); 296 out.write((int) (v >> 24L)); 297 out.write((int) (v >> 16L)); 298 out.write((int) (v >> 8L)); 299 out.write((int) (v)); 300 } else { 301 out.write(0xFF); 302 out.write((int) (v >> 56L)); 303 out.write((int) (v >> 48L)); 304 out.write((int) (v >> 40L)); 305 out.write((int) (v >> 32L)); 306 out.write((int) (v >> 24L)); 307 out.write((int) (v >> 16L)); 308 out.write((int) (v >> 8L)); 309 out.write((int) (v)); 310 } 311 } 312 313 /** 314 * Write the given unsigned long value to this data output stream. From one 315 * to nine bytes are written, in big-endian order, as follows: 316 * <UL> 317 * 318 * <LI> 319 * If 0 ≤ <code>v</code> ≤ 127, then one byte is written, containing 0 (1 320 * bit) followed by <code>v</code> (7 bits). 321 * 322 * <LI> 323 * Else if 128 ≤ <code>v</code> ≤ 16383, then two bytes are written, 324 * containing 10 (2 bits) followed by <code>v</code> (14 bits). 325 * 326 * <LI> 327 * Else if 16384 ≤ <code>v</code> ≤ 2097151, then three bytes are written, 328 * containing 110 (3 bits) followed by <code>v</code> (21 bits). 329 * 330 * <LI> 331 * Else if 2097152 ≤ <code>v</code> ≤ 268435455, then four bytes are 332 * written, containing 1110 (4 bits) followed by <code>v</code> (28 bits). 333 * 334 * <LI> 335 * Else if 268435456 ≤ <code>v</code> ≤ 34359738367, then five bytes are 336 * written, containing 11110 (5 bits) followed by <code>v</code> (35 bits). 337 * 338 * <LI> 339 * Else if 34359738368 ≤ <code>v</code> ≤ 4398046511103, then six bytes 340 * are written, containing 111110 (6 bits) followed by <code>v</code> (42 bits). 341 * 342 * <LI> 343 * Else if 4398046511104 ≤ <code>v</code> ≤ 562949953421311, then seven 344 * bytes are written, containing 1111110 (7 bits) followed by <code>v</code> (49 345 * bits). 346 * 347 * <LI> 348 * Else if 562949953421312 ≤ <code>v</code> ≤ 72057594037927935, then 349 * eight bytes are written, containing 11111110 (8 bits) followed by 350 * <code>v</code> (56 bits). 351 * 352 * <LI> 353 * Else nine bytes are written, containing 11111111 (8 bits) followed by 354 * <code>v</code> (64 bits). 355 * </UL> 356 * 357 * @param v Integer value. 358 * @throws java.io.IOException Thrown if an I/O error occurred. 359 * @throws java.io.IOException if any. 360 */ 361 public void writeUnsignedLong(long v) 362 throws IOException { 363 if (0L <= v && v <= 127L) { 364 out.write((int) (v)); 365 } else if (128L <= v && v <= 16383L) { 366 out.write((int) (v >> 8L) | 0x80); 367 out.write((int) (v)); 368 } else if (16384L <= v && v <= 2097151L) { 369 out.write((int) (v >> 16L) | 0xC0); 370 out.write((int) (v >> 8L)); 371 out.write((int) (v)); 372 } else if (2097152L <= v && v <= 268435455L) { 373 out.write((int) (v >> 24L) | 0xE0); 374 out.write((int) (v >> 16L)); 375 out.write((int) (v >> 8L)); 376 out.write((int) (v)); 377 } else if (268435456L <= v && v <= 34359738367L) { 378 out.write((int) (v >> 32L) | 0xF0); 379 out.write((int) (v >> 24L)); 380 out.write((int) (v >> 16L)); 381 out.write((int) (v >> 8L)); 382 out.write((int) (v)); 383 } else if (34359738368L <= v && v <= 4398046511103L) { 384 out.write((int) (v >> 40L) | 0xF8); 385 out.write((int) (v >> 32L)); 386 out.write((int) (v >> 24L)); 387 out.write((int) (v >> 16L)); 388 out.write((int) (v >> 8L)); 389 out.write((int) (v)); 390 } else if (4398046511104L <= v && v <= 562949953421311L) { 391 out.write((int) (v >> 48L) | 0xFC); 392 out.write((int) (v >> 40L)); 393 out.write((int) (v >> 32L)); 394 out.write((int) (v >> 24L)); 395 out.write((int) (v >> 16L)); 396 out.write((int) (v >> 8L)); 397 out.write((int) (v)); 398 } else if (562949953421312L <= v && v <= 72057594037927935L) { 399 out.write(0xFE); 400 out.write((int) (v >> 48L)); 401 out.write((int) (v >> 40L)); 402 out.write((int) (v >> 32L)); 403 out.write((int) (v >> 24L)); 404 out.write((int) (v >> 16L)); 405 out.write((int) (v >> 8L)); 406 out.write((int) (v)); 407 } else { 408 out.write(0xFF); 409 out.write((int) (v >> 56L)); 410 out.write((int) (v >> 48L)); 411 out.write((int) (v >> 40L)); 412 out.write((int) (v >> 32L)); 413 out.write((int) (v >> 24L)); 414 out.write((int) (v >> 16L)); 415 out.write((int) (v >> 8L)); 416 out.write((int) (v)); 417 } 418 } 419 420 /** 421 * Write the given float value to this data output stream. Four bytes are 422 * written in big-endian order containing 423 * <code>Float.floatToRawIntBits(v)</code>. 424 * 425 * @param v Float value. 426 * @throws java.io.IOException Thrown if an I/O error occurred. 427 * @throws java.io.IOException if any. 428 */ 429 public void writeFloat(float v) 430 throws IOException { 431 int x = Float.floatToRawIntBits(v); 432 out.write(x >> 24); 433 out.write(x >> 16); 434 out.write(x >> 8); 435 out.write(x); 436 } 437 438 /** 439 * Write the given double value to this data output stream. Eight bytes are 440 * written in big-endian order containing 441 * <code>Double.doubleToRawLongBits(v)</code>. 442 * 443 * @param v Double value. 444 * @throws java.io.IOException Thrown if an I/O error occurred. 445 * @throws java.io.IOException if any. 446 */ 447 public void writeDouble(double v) 448 throws IOException { 449 long x = Double.doubleToRawLongBits(v); 450 out.write((int) (x >> 56L)); 451 out.write((int) (x >> 48L)); 452 out.write((int) (x >> 40L)); 453 out.write((int) (x >> 32L)); 454 out.write((int) (x >> 24L)); 455 out.write((int) (x >> 16L)); 456 out.write((int) (x >> 8L)); 457 out.write((int) (x)); 458 } 459 460 /** 461 * Write the given string value to this data output stream. The length of 462 * the string is written using <code>writeUnsignedInt()</code>, then each 463 * character of the string is written using <code>writeUnsignedInt()</code>. 464 * 465 * @param v String value. 466 * @throws java.io.IOException Thrown if an I/O error occurred. 467 * @throws java.io.IOException if any. 468 */ 469 public void writeString(String v) 470 throws IOException { 471 int n = v.length(); 472 writeUnsignedInt(n); 473 for (int i = 0; i < n; ++i) { 474 writeUnsignedInt(v.charAt(i)); 475 } 476 } 477 478 }