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 }