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