1 /*
2 * Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26 package javax.imageio.stream;
27
28 import java.io.IOException;
29 import java.io.UTFDataFormatException;
30 import java.nio.ByteOrder;
31
32 /**
33 * An abstract class implementing the <code>ImageOutputStream</code> interface.
34 * This class is designed to reduce the number of methods that must
35 * be implemented by subclasses.
36 *
37 */
38 public abstract class ImageOutputStreamImpl
39 extends ImageInputStreamImpl
40 implements ImageOutputStream {
41
42 /**
43 * Constructs an <code>ImageOutputStreamImpl</code>.
44 */
45 public ImageOutputStreamImpl() {
46 }
47
48 public abstract void write(int b) throws IOException;
49
50 public void write(byte b[]) throws IOException {
51 write(b, 0, b.length);
52 }
53
54 public abstract void write(byte b[], int off, int len) throws IOException;
55
56 public void writeBoolean(boolean v) throws IOException {
57 write(v ? 1 : 0);
58 }
59
60 public void writeByte(int v) throws IOException {
61 write(v);
62 }
63
64 public void writeShort(int v) throws IOException {
65 if (byteOrder == ByteOrder.BIG_ENDIAN) {
66 byteBuf[0] = (byte)(v >>> 8);
67 byteBuf[1] = (byte)(v >>> 0);
68 } else {
69 byteBuf[0] = (byte)(v >>> 0);
70 byteBuf[1] = (byte)(v >>> 8);
71 }
72 write(byteBuf, 0, 2);
73 }
74
75 public void writeChar(int v) throws IOException {
76 writeShort(v);
77 }
78
79 public void writeInt(int v) throws IOException {
80 if (byteOrder == ByteOrder.BIG_ENDIAN) {
81 byteBuf[0] = (byte)(v >>> 24);
82 byteBuf[1] = (byte)(v >>> 16);
83 byteBuf[2] = (byte)(v >>> 8);
84 byteBuf[3] = (byte)(v >>> 0);
85 } else {
86 byteBuf[0] = (byte)(v >>> 0);
87 byteBuf[1] = (byte)(v >>> 8);
88 byteBuf[2] = (byte)(v >>> 16);
89 byteBuf[3] = (byte)(v >>> 24);
90 }
91 write(byteBuf, 0, 4);
92 }
93
94 public void writeLong(long v) throws IOException {
95 if (byteOrder == ByteOrder.BIG_ENDIAN) {
96 byteBuf[0] = (byte)(v >>> 56);
97 byteBuf[1] = (byte)(v >>> 48);
98 byteBuf[2] = (byte)(v >>> 40);
99 byteBuf[3] = (byte)(v >>> 32);
100 byteBuf[4] = (byte)(v >>> 24);
101 byteBuf[5] = (byte)(v >>> 16);
102 byteBuf[6] = (byte)(v >>> 8);
103 byteBuf[7] = (byte)(v >>> 0);
104 } else {
105 byteBuf[0] = (byte)(v >>> 0);
106 byteBuf[1] = (byte)(v >>> 8);
107 byteBuf[2] = (byte)(v >>> 16);
108 byteBuf[3] = (byte)(v >>> 24);
109 byteBuf[4] = (byte)(v >>> 32);
110 byteBuf[5] = (byte)(v >>> 40);
111 byteBuf[6] = (byte)(v >>> 48);
112 byteBuf[7] = (byte)(v >>> 56);
113 }
114 // REMIND: Once 6277756 is fixed, we should do a bulk write of all 8
115 // bytes here as we do in writeShort() and writeInt() for even better
116 // performance. For now, two bulk writes of 4 bytes each is still
117 // faster than 8 individual write() calls (see 6347575 for details).
118 write(byteBuf, 0, 4);
119 write(byteBuf, 4, 4);
120 }
121
122 public void writeFloat(float v) throws IOException {
123 writeInt(Float.floatToIntBits(v));
124 }
125
126 public void writeDouble(double v) throws IOException {
127 writeLong(Double.doubleToLongBits(v));
128 }
129
130 public void writeBytes(String s) throws IOException {
131 int len = s.length();
132 for (int i = 0 ; i < len ; i++) {
133 write((byte)s.charAt(i));
134 }
135 }
136
137 public void writeChars(String s) throws IOException {
138 int len = s.length();
139
140 byte[] b = new byte[len*2];
141 int boff = 0;
142 if (byteOrder == ByteOrder.BIG_ENDIAN) {
143 for (int i = 0; i < len ; i++) {
144 int v = s.charAt(i);
145 b[boff++] = (byte)(v >>> 8);
146 b[boff++] = (byte)(v >>> 0);
147 }
148 } else {
149 for (int i = 0; i < len ; i++) {
150 int v = s.charAt(i);
151 b[boff++] = (byte)(v >>> 0);
152 b[boff++] = (byte)(v >>> 8);
153 }
154 }
155
156 write(b, 0, len*2);
157 }
158
159 public void writeUTF(String s) throws IOException {
160 int strlen = s.length();
161 int utflen = 0;
162 char[] charr = new char[strlen];
163 int c, boff = 0;
164
165 s.getChars(0, strlen, charr, 0);
166
167 for (int i = 0; i < strlen; i++) {
168 c = charr[i];
169 if ((c >= 0x0001) && (c <= 0x007F)) {
170 utflen++;
171 } else if (c > 0x07FF) {
172 utflen += 3;
173 } else {
174 utflen += 2;
175 }
176 }
177
178 if (utflen > 65535) {
179 throw new UTFDataFormatException("utflen > 65536!");
180 }
181
182 byte[] b = new byte[utflen+2];
183 b[boff++] = (byte) ((utflen >>> 8) & 0xFF);
184 b[boff++] = (byte) ((utflen >>> 0) & 0xFF);
185 for (int i = 0; i < strlen; i++) {
186 c = charr[i];
187 if ((c >= 0x0001) && (c <= 0x007F)) {
188 b[boff++] = (byte) c;
189 } else if (c > 0x07FF) {
190 b[boff++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
191 b[boff++] = (byte) (0x80 | ((c >> 6) & 0x3F));
192 b[boff++] = (byte) (0x80 | ((c >> 0) & 0x3F));
193 } else {
194 b[boff++] = (byte) (0xC0 | ((c >> 6) & 0x1F));
195 b[boff++] = (byte) (0x80 | ((c >> 0) & 0x3F));
196 }
197 }
198 write(b, 0, utflen + 2);
199 }
200
201 public void writeShorts(short[] s, int off, int len) throws IOException {
202 // Fix 4430357 - if off + len < 0, overflow occurred
203 if (off < 0 || len < 0 || off + len > s.length || off + len < 0) {
204 throw new IndexOutOfBoundsException
205 ("off < 0 || len < 0 || off + len > s.length!");
206 }
207
208 byte[] b = new byte[len*2];
209 int boff = 0;
210 if (byteOrder == ByteOrder.BIG_ENDIAN) {
211 for (int i = 0; i < len; i++) {
212 short v = s[off + i];
213 b[boff++] = (byte)(v >>> 8);
214 b[boff++] = (byte)(v >>> 0);
215 }
216 } else {
217 for (int i = 0; i < len; i++) {
218 short v = s[off + i];
219 b[boff++] = (byte)(v >>> 0);
220 b[boff++] = (byte)(v >>> 8);
221 }
222 }
223
224 write(b, 0, len*2);
225 }
226
227 public void writeChars(char[] c, int off, int len) throws IOException {
228 // Fix 4430357 - if off + len < 0, overflow occurred
229 if (off < 0 || len < 0 || off + len > c.length || off + len < 0) {
230 throw new IndexOutOfBoundsException
231 ("off < 0 || len < 0 || off + len > c.length!");
232 }
233
234 byte[] b = new byte[len*2];
235 int boff = 0;
236 if (byteOrder == ByteOrder.BIG_ENDIAN) {
237 for (int i = 0; i < len; i++) {
238 char v = c[off + i];
239 b[boff++] = (byte)(v >>> 8);
240 b[boff++] = (byte)(v >>> 0);
241 }
242 } else {
243 for (int i = 0; i < len; i++) {
244 char v = c[off + i];
245 b[boff++] = (byte)(v >>> 0);
246 b[boff++] = (byte)(v >>> 8);
247 }
248 }
249
250 write(b, 0, len*2);
251 }
252
253 public void writeInts(int[] i, int off, int len) throws IOException {
254 // Fix 4430357 - if off + len < 0, overflow occurred
255 if (off < 0 || len < 0 || off + len > i.length || off + len < 0) {
256 throw new IndexOutOfBoundsException
257 ("off < 0 || len < 0 || off + len > i.length!");
258 }
259
260 byte[] b = new byte[len*4];
261 int boff = 0;
262 if (byteOrder == ByteOrder.BIG_ENDIAN) {
263 for (int j = 0; j < len; j++) {
264 int v = i[off + j];
265 b[boff++] = (byte)(v >>> 24);
266 b[boff++] = (byte)(v >>> 16);
267 b[boff++] = (byte)(v >>> 8);
268 b[boff++] = (byte)(v >>> 0);
269 }
270 } else {
271 for (int j = 0; j < len; j++) {
272 int v = i[off + j];
273 b[boff++] = (byte)(v >>> 0);
274 b[boff++] = (byte)(v >>> 8);
275 b[boff++] = (byte)(v >>> 16);
276 b[boff++] = (byte)(v >>> 24);
277 }
278 }
279
280 write(b, 0, len*4);
281 }
282
283 public void writeLongs(long[] l, int off, int len) throws IOException {
284 // Fix 4430357 - if off + len < 0, overflow occurred
285 if (off < 0 || len < 0 || off + len > l.length || off + len < 0) {
286 throw new IndexOutOfBoundsException
287 ("off < 0 || len < 0 || off + len > l.length!");
288 }
289
290 byte[] b = new byte[len*8];
291 int boff = 0;
292 if (byteOrder == ByteOrder.BIG_ENDIAN) {
293 for (int i = 0; i < len; i++) {
294 long v = l[off + i];
295 b[boff++] = (byte)(v >>> 56);
296 b[boff++] = (byte)(v >>> 48);
297 b[boff++] = (byte)(v >>> 40);
298 b[boff++] = (byte)(v >>> 32);
299 b[boff++] = (byte)(v >>> 24);
300 b[boff++] = (byte)(v >>> 16);
301 b[boff++] = (byte)(v >>> 8);
302 b[boff++] = (byte)(v >>> 0);
303 }
304 } else {
305 for (int i = 0; i < len; i++) {
306 long v = l[off + i];
307 b[boff++] = (byte)(v >>> 0);
308 b[boff++] = (byte)(v >>> 8);
309 b[boff++] = (byte)(v >>> 16);
310 b[boff++] = (byte)(v >>> 24);
311 b[boff++] = (byte)(v >>> 32);
312 b[boff++] = (byte)(v >>> 40);
313 b[boff++] = (byte)(v >>> 48);
314 b[boff++] = (byte)(v >>> 56);
315 }
316 }
317
318 write(b, 0, len*8);
319 }
320
321 public void writeFloats(float[] f, int off, int len) throws IOException {
322 // Fix 4430357 - if off + len < 0, overflow occurred
323 if (off < 0 || len < 0 || off + len > f.length || off + len < 0) {
324 throw new IndexOutOfBoundsException
325 ("off < 0 || len < 0 || off + len > f.length!");
326 }
327
328 byte[] b = new byte[len*4];
329 int boff = 0;
330 if (byteOrder == ByteOrder.BIG_ENDIAN) {
331 for (int i = 0; i < len; i++) {
332 int v = Float.floatToIntBits(f[off + i]);
333 b[boff++] = (byte)(v >>> 24);
334 b[boff++] = (byte)(v >>> 16);
335 b[boff++] = (byte)(v >>> 8);
336 b[boff++] = (byte)(v >>> 0);
337 }
338 } else {
339 for (int i = 0; i < len; i++) {
340 int v = Float.floatToIntBits(f[off + i]);
341 b[boff++] = (byte)(v >>> 0);
342 b[boff++] = (byte)(v >>> 8);
343 b[boff++] = (byte)(v >>> 16);
344 b[boff++] = (byte)(v >>> 24);
345 }
346 }
347
348 write(b, 0, len*4);
349 }
350
351 public void writeDoubles(double[] d, int off, int len) throws IOException {
352 // Fix 4430357 - if off + len < 0, overflow occurred
353 if (off < 0 || len < 0 || off + len > d.length || off + len < 0) {
354 throw new IndexOutOfBoundsException
355 ("off < 0 || len < 0 || off + len > d.length!");
356 }
357
358 byte[] b = new byte[len*8];
359 int boff = 0;
360 if (byteOrder == ByteOrder.BIG_ENDIAN) {
361 for (int i = 0; i < len; i++) {
362 long v = Double.doubleToLongBits(d[off + i]);
363 b[boff++] = (byte)(v >>> 56);
364 b[boff++] = (byte)(v >>> 48);
365 b[boff++] = (byte)(v >>> 40);
366 b[boff++] = (byte)(v >>> 32);
367 b[boff++] = (byte)(v >>> 24);
368 b[boff++] = (byte)(v >>> 16);
369 b[boff++] = (byte)(v >>> 8);
370 b[boff++] = (byte)(v >>> 0);
371 }
372 } else {
373 for (int i = 0; i < len; i++) {
374 long v = Double.doubleToLongBits(d[off + i]);
375 b[boff++] = (byte)(v >>> 0);
376 b[boff++] = (byte)(v >>> 8);
377 b[boff++] = (byte)(v >>> 16);
378 b[boff++] = (byte)(v >>> 24);
379 b[boff++] = (byte)(v >>> 32);
380 b[boff++] = (byte)(v >>> 40);
381 b[boff++] = (byte)(v >>> 48);
382 b[boff++] = (byte)(v >>> 56);
383 }
384 }
385
386 write(b, 0, len*8);
387 }
388
389 public void writeBit(int bit) throws IOException {
390 writeBits((1L & bit), 1);
391 }
392
393 public void writeBits(long bits, int numBits) throws IOException {
394 checkClosed();
395
396 if (numBits < 0 || numBits > 64) {
397 throw new IllegalArgumentException("Bad value for numBits!");
398 }
399 if (numBits == 0) {
400 return;
401 }
402
403 // Prologue: deal with pre-existing bits
404
405 // Bug 4499158, 4507868 - if we're at the beginning of the stream
406 // and the bit offset is 0, there can't be any pre-existing bits
407 if ((getStreamPosition() > 0) || (bitOffset > 0)) {
408 int offset = bitOffset; // read() will reset bitOffset
409 int partialByte = read();
410 if (partialByte != -1) {
411 seek(getStreamPosition() - 1);
412 } else {
413 partialByte = 0;
414 }
415
416 if (numBits + offset < 8) {
417 // Notch out the partial byte and drop in the new bits
418 int shift = 8 - (offset+numBits);
419 int mask = -1 >>> (32 - numBits);
420 partialByte &= ~(mask << shift); // Clear out old bits
421 partialByte |= ((bits & mask) << shift); // Or in new ones
422 write(partialByte);
423 seek(getStreamPosition() - 1);
424 bitOffset = offset + numBits;
425 numBits = 0; // Signal that we are done
426 } else {
427 // Fill out the partial byte and reduce numBits
428 int num = 8 - offset;
429 int mask = -1 >>> (32 - num);
430 partialByte &= ~mask; // Clear out bits
431 partialByte |= ((bits >> (numBits - num)) & mask);
432 // Note that bitOffset is already 0, so there is no risk
433 // of this advancing to the next byte
434 write(partialByte);
435 numBits -= num;
436 }
437 }
438
439 // Now write any whole bytes
440 if (numBits > 7) {
441 int extra = numBits % 8;
442 for (int numBytes = numBits / 8; numBytes > 0; numBytes--) {
443 int shift = (numBytes-1)*8+extra;
444 int value = (int) ((shift == 0)
445 ? bits & 0xFF
446 : (bits>>shift) & 0xFF);
447 write(value);
448 }
449 numBits = extra;
450 }
451
452 // Epilogue: write out remaining partial byte, if any
453 // Note that we may be at EOF, in which case we pad with 0,
454 // or not, in which case we must preserve the existing bits
455 if (numBits != 0) {
456 // If we are not at the end of the file, read the current byte
457 // If we are at the end of the file, initialize our byte to 0.
458 int partialByte = 0;
459 partialByte = read();
460 if (partialByte != -1) {
461 seek(getStreamPosition() - 1);
462 }
463 // Fix 4494976: writeBit(int) does not pad the remainder
464 // of the current byte with 0s
465 else { // EOF
466 partialByte = 0;
467 }
468
469 int shift = 8 - numBits;
470 int mask = -1 >>> (32 - numBits);
471 partialByte &= ~(mask << shift);
472 partialByte |= (bits & mask) << shift;
473 // bitOffset is always already 0 when we get here.
474 write(partialByte);
475 seek(getStreamPosition() - 1);
476 bitOffset = numBits;
477 }
478 }
479
480 /**
481 * If the bit offset is non-zero, forces the remaining bits
482 * in the current byte to 0 and advances the stream position
483 * by one. This method should be called by subclasses at the
484 * beginning of the <code>write(int)</code> and
485 * <code>write(byte[], int, int)</code> methods.
486 *
487 * @exception IOException if an I/O error occurs.
488 */
489 protected final void flushBits() throws IOException {
490 checkClosed();
491 if (bitOffset != 0) {
492 int offset = bitOffset;
493 int partialByte = read(); // Sets bitOffset to 0
494 if (partialByte < 0) {
495 // Fix 4465683: When bitOffset is set
496 // to something non-zero beyond EOF,
497 // we should set that whole byte to
498 // zero and write it to stream.
499 partialByte = 0;
500 bitOffset = 0;
501 }
502 else {
503 seek(getStreamPosition() - 1);
504 partialByte &= -1 << (8 - offset);
505 }
506 write(partialByte);
507 }
508 }
509
510 }