- /*
- * @(#)ImageOutputStreamImpl.java 1.23 03/01/23
- *
- * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
- * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- */
-
- package javax.imageio.stream;
-
- import java.io.File;
- import java.io.IOException;
- import java.io.UTFDataFormatException;
- import java.nio.ByteOrder;
-
- /**
- * An abstract class implementing the <code>ImageOutputStream</code> interface.
- * This class is designed to reduce the number of methods that must
- * be implemented by subclasses.
- *
- * @version 0.5
- */
- public abstract class ImageOutputStreamImpl
- extends ImageInputStreamImpl
- implements ImageOutputStream {
-
- /**
- * Constructs an <code>ImageOutputStreamImpl</code>.
- */
- public ImageOutputStreamImpl() {
- }
-
- public abstract void write(int b) throws IOException;
-
- public void write(byte b[]) throws IOException {
- write(b, 0, b.length);
- }
-
- public abstract void write(byte b[], int off, int len) throws IOException;
-
- public void writeBoolean(boolean v) throws IOException {
- write(v ? 1 : 0);
- }
-
- public void writeByte(int v) throws IOException {
- write(v);
- }
-
- public void writeShort(int v) throws IOException {
- if (byteOrder == ByteOrder.BIG_ENDIAN) {
- write((v >>> 8) & 0xFF);
- write((v >>> 0) & 0xFF);
- } else {
- write((v >>> 0) & 0xFF);
- write((v >>> 8) & 0xFF);
- }
- }
-
- public void writeChar(int v) throws IOException {
- writeShort(v);
- }
-
- public void writeInt(int v) throws IOException {
- if (byteOrder == ByteOrder.BIG_ENDIAN) {
- write((v >>> 24) & 0xFF);
- write((v >>> 16) & 0xFF);
- write((v >>> 8) & 0xFF);
- write((v >>> 0) & 0xFF);
- } else {
- write((v >>> 0) & 0xFF);
- write((v >>> 8) & 0xFF);
- write((v >>> 16) & 0xFF);
- write((v >>> 24) & 0xFF);
- }
- }
-
- public void writeLong(long v) throws IOException {
- if (byteOrder == ByteOrder.BIG_ENDIAN) {
- write((int)(v >>> 56) & 0xFF);
- write((int)(v >>> 48) & 0xFF);
- write((int)(v >>> 40) & 0xFF);
- write((int)(v >>> 32) & 0xFF);
- write((int)(v >>> 24) & 0xFF);
- write((int)(v >>> 16) & 0xFF);
- write((int)(v >>> 8) & 0xFF);
- write((int)(v >>> 0) & 0xFF);
- } else {
- write((int)(v >>> 0) & 0xFF);
- write((int)(v >>> 8) & 0xFF);
- write((int)(v >>> 16) & 0xFF);
- write((int)(v >>> 24) & 0xFF);
- write((int)(v >>> 32) & 0xFF);
- write((int)(v >>> 40) & 0xFF);
- write((int)(v >>> 48) & 0xFF);
- write((int)(v >>> 56) & 0xFF);
- }
- }
-
- public void writeFloat(float v) throws IOException {
- writeInt(Float.floatToIntBits(v));
- }
-
- public void writeDouble(double v) throws IOException {
- writeLong(Double.doubleToLongBits(v));
- }
-
- public void writeBytes(String s) throws IOException {
- int len = s.length();
- for (int i = 0 ; i < len ; i++) {
- write((byte)s.charAt(i));
- }
- }
-
- public void writeChars(String s) throws IOException {
- int len = s.length();
-
- byte[] b = new byte[len*2];
- int boff = 0;
- if (byteOrder == ByteOrder.BIG_ENDIAN) {
- for (int i = 0; i < len ; i++) {
- int v = s.charAt(i);
- b[boff++] = (byte)(v >>> 8);
- b[boff++] = (byte)(v >>> 0);
- }
- } else {
- for (int i = 0; i < len ; i++) {
- int v = s.charAt(i);
- b[boff++] = (byte)(v >>> 0);
- b[boff++] = (byte)(v >>> 8);
- }
- }
-
- write(b, 0, len*2);
- }
-
- public void writeUTF(String s) throws IOException {
- int strlen = s.length();
- int utflen = 0;
- char[] charr = new char[strlen];
- int c, boff = 0;
-
- s.getChars(0, strlen, charr, 0);
-
- for (int i = 0; i < strlen; i++) {
- c = charr[i];
- if ((c >= 0x0001) && (c <= 0x007F)) {
- utflen++;
- } else if (c > 0x07FF) {
- utflen += 3;
- } else {
- utflen += 2;
- }
- }
-
- if (utflen > 65535) {
- throw new UTFDataFormatException("utflen > 65536!");
- }
-
- byte[] b = new byte[utflen+2];
- b[boff++] = (byte) ((utflen >>> 8) & 0xFF);
- b[boff++] = (byte) ((utflen >>> 0) & 0xFF);
- for (int i = 0; i < strlen; i++) {
- c = charr[i];
- if ((c >= 0x0001) && (c <= 0x007F)) {
- b[boff++] = (byte) c;
- } else if (c > 0x07FF) {
- b[boff++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
- b[boff++] = (byte) (0x80 | ((c >> 6) & 0x3F));
- b[boff++] = (byte) (0x80 | ((c >> 0) & 0x3F));
- } else {
- b[boff++] = (byte) (0xC0 | ((c >> 6) & 0x1F));
- b[boff++] = (byte) (0x80 | ((c >> 0) & 0x3F));
- }
- }
- write(b, 0, utflen + 2);
- }
-
- public void writeShorts(short[] s, int off, int len) throws IOException {
- // Fix 4430357 - if off + len < 0, overflow occurred
- if (off < 0 || len < 0 || off + len > s.length || off + len < 0) {
- throw new IndexOutOfBoundsException
- ("off < 0 || len < 0 || off + len > s.length!");
- }
-
- byte[] b = new byte[len*2];
- int boff = 0;
- if (byteOrder == ByteOrder.BIG_ENDIAN) {
- for (int i = 0; i < len; i++) {
- short v = s[off + i];
- b[boff++] = (byte)(v >>> 8);
- b[boff++] = (byte)(v >>> 0);
- }
- } else {
- for (int i = 0; i < len; i++) {
- short v = s[off + i];
- b[boff++] = (byte)(v >>> 0);
- b[boff++] = (byte)(v >>> 8);
- }
- }
-
- write(b, 0, len*2);
- }
-
- public void writeChars(char[] c, int off, int len) throws IOException {
- // Fix 4430357 - if off + len < 0, overflow occurred
- if (off < 0 || len < 0 || off + len > c.length || off + len < 0) {
- throw new IndexOutOfBoundsException
- ("off < 0 || len < 0 || off + len > c.length!");
- }
-
- byte[] b = new byte[len*2];
- int boff = 0;
- if (byteOrder == ByteOrder.BIG_ENDIAN) {
- for (int i = 0; i < len; i++) {
- char v = c[off + i];
- b[boff++] = (byte)(v >>> 8);
- b[boff++] = (byte)(v >>> 0);
- }
- } else {
- for (int i = 0; i < len; i++) {
- char v = c[off + i];
- b[boff++] = (byte)(v >>> 0);
- b[boff++] = (byte)(v >>> 8);
- }
- }
-
- write(b, 0, len*2);
- }
-
- public void writeInts(int[] i, int off, int len) throws IOException {
- // Fix 4430357 - if off + len < 0, overflow occurred
- if (off < 0 || len < 0 || off + len > i.length || off + len < 0) {
- throw new IndexOutOfBoundsException
- ("off < 0 || len < 0 || off + len > i.length!");
- }
-
- byte[] b = new byte[len*4];
- int boff = 0;
- if (byteOrder == ByteOrder.BIG_ENDIAN) {
- for (int j = 0; j < len; j++) {
- int v = i[off + j];
- b[boff++] = (byte)(v >>> 24);
- b[boff++] = (byte)(v >>> 16);
- b[boff++] = (byte)(v >>> 8);
- b[boff++] = (byte)(v >>> 0);
- }
- } else {
- for (int j = 0; j < len; j++) {
- int v = i[off + j];
- b[boff++] = (byte)(v >>> 0);
- b[boff++] = (byte)(v >>> 8);
- b[boff++] = (byte)(v >>> 16);
- b[boff++] = (byte)(v >>> 24);
- }
- }
-
- write(b, 0, len*4);
- }
-
- public void writeLongs(long[] l, int off, int len) throws IOException {
- // Fix 4430357 - if off + len < 0, overflow occurred
- if (off < 0 || len < 0 || off + len > l.length || off + len < 0) {
- throw new IndexOutOfBoundsException
- ("off < 0 || len < 0 || off + len > l.length!");
- }
-
- byte[] b = new byte[len*8];
- int boff = 0;
- if (byteOrder == ByteOrder.BIG_ENDIAN) {
- for (int i = 0; i < len; i++) {
- long v = l[off + i];
- b[boff++] = (byte)(v >>> 56);
- b[boff++] = (byte)(v >>> 48);
- b[boff++] = (byte)(v >>> 40);
- b[boff++] = (byte)(v >>> 32);
- b[boff++] = (byte)(v >>> 24);
- b[boff++] = (byte)(v >>> 16);
- b[boff++] = (byte)(v >>> 8);
- b[boff++] = (byte)(v >>> 0);
- }
- } else {
- for (int i = 0; i < len; i++) {
- long v = l[off + i];
- b[boff++] = (byte)(v >>> 0);
- b[boff++] = (byte)(v >>> 8);
- b[boff++] = (byte)(v >>> 16);
- b[boff++] = (byte)(v >>> 24);
- b[boff++] = (byte)(v >>> 32);
- b[boff++] = (byte)(v >>> 40);
- b[boff++] = (byte)(v >>> 48);
- b[boff++] = (byte)(v >>> 56);
- }
- }
-
- write(b, 0, len*8);
- }
-
- public void writeFloats(float[] f, int off, int len) throws IOException {
- // Fix 4430357 - if off + len < 0, overflow occurred
- if (off < 0 || len < 0 || off + len > f.length || off + len < 0) {
- throw new IndexOutOfBoundsException
- ("off < 0 || len < 0 || off + len > f.length!");
- }
-
- byte[] b = new byte[len*4];
- int boff = 0;
- if (byteOrder == ByteOrder.BIG_ENDIAN) {
- for (int i = 0; i < len; i++) {
- int v = Float.floatToIntBits(f[off + i]);
- b[boff++] = (byte)(v >>> 24);
- b[boff++] = (byte)(v >>> 16);
- b[boff++] = (byte)(v >>> 8);
- b[boff++] = (byte)(v >>> 0);
- }
- } else {
- for (int i = 0; i < len; i++) {
- int v = Float.floatToIntBits(f[off + i]);
- b[boff++] = (byte)(v >>> 0);
- b[boff++] = (byte)(v >>> 8);
- b[boff++] = (byte)(v >>> 16);
- b[boff++] = (byte)(v >>> 24);
- }
- }
-
- write(b, 0, len*4);
- }
-
- public void writeDoubles(double[] d, int off, int len) throws IOException {
- // Fix 4430357 - if off + len < 0, overflow occurred
- if (off < 0 || len < 0 || off + len > d.length || off + len < 0) {
- throw new IndexOutOfBoundsException
- ("off < 0 || len < 0 || off + len > d.length!");
- }
-
- byte[] b = new byte[len*8];
- int boff = 0;
- if (byteOrder == ByteOrder.BIG_ENDIAN) {
- for (int i = 0; i < len; i++) {
- long v = Double.doubleToLongBits(d[off + i]);
- b[boff++] = (byte)(v >>> 56);
- b[boff++] = (byte)(v >>> 48);
- b[boff++] = (byte)(v >>> 40);
- b[boff++] = (byte)(v >>> 32);
- b[boff++] = (byte)(v >>> 24);
- b[boff++] = (byte)(v >>> 16);
- b[boff++] = (byte)(v >>> 8);
- b[boff++] = (byte)(v >>> 0);
- }
- } else {
- for (int i = 0; i < len; i++) {
- long v = Double.doubleToLongBits(d[off + i]);
- b[boff++] = (byte)(v >>> 0);
- b[boff++] = (byte)(v >>> 8);
- b[boff++] = (byte)(v >>> 16);
- b[boff++] = (byte)(v >>> 24);
- b[boff++] = (byte)(v >>> 32);
- b[boff++] = (byte)(v >>> 40);
- b[boff++] = (byte)(v >>> 48);
- b[boff++] = (byte)(v >>> 56);
- }
- }
-
- write(b, 0, len*8);
- }
-
- public void writeBit(int bit) throws IOException {
- writeBits((1L & bit), 1);
- }
-
- public void writeBits(long bits, int numBits) throws IOException {
- checkClosed();
-
- if (numBits < 0 || numBits > 64) {
- throw new IllegalArgumentException("Bad value for numBits!");
- }
- if (numBits == 0) {
- return;
- }
-
- // Prologue: deal with pre-existing bits
-
- // Bug 4499158, 4507868 - if we're at the beginning of the stream
- // and the bit offset is 0, there can't be any pre-existing bits
- if ((getStreamPosition() > 0) || (bitOffset > 0)) {
- int offset = bitOffset; // read() will reset bitOffset
- int partialByte = read();
- if (partialByte != -1) {
- seek(getStreamPosition() - 1);
- } else {
- partialByte = 0;
- }
-
- if (numBits + offset < 8) {
- // Notch out the partial byte and drop in the new bits
- int shift = 8 - (offset+numBits);
- int mask = -1 >>> (32 - numBits);
- partialByte &= ~(mask << shift); // Clear out old bits
- partialByte |= ((bits & mask) << shift); // Or in new ones
- write(partialByte);
- seek(getStreamPosition() - 1);
- bitOffset = offset + numBits;
- numBits = 0; // Signal that we are done
- } else {
- // Fill out the partial byte and reduce numBits
- int num = 8 - offset;
- int mask = -1 >>> (32 - num);
- partialByte &= ~mask; // Clear out bits
- partialByte |= ((bits >> (numBits - num)) & mask);
- // Note that bitOffset is already 0, so there is no risk
- // of this advancing to the next byte
- write(partialByte);
- numBits -= num;
- }
- }
-
- // Now write any whole bytes
- if (numBits > 7) {
- int extra = numBits % 8;
- for (int numBytes = numBits / 8; numBytes > 0; numBytes--) {
- int shift = (numBytes-1)*8+extra;
- int value = (int) ((shift == 0)
- ? bits & 0xFF
- : (bits>>shift) & 0xFF);
- write(value);
- }
- numBits = extra;
- }
-
- // Epilogue: write out remaining partial byte, if any
- // Note that we may be at EOF, in which case we pad with 0,
- // or not, in which case we must preserve the existing bits
- if (numBits != 0) {
- // If we are not at the end of the file, read the current byte
- // If we are at the end of the file, initialize our byte to 0.
- int partialByte = 0;
- partialByte = read();
- if (partialByte != -1) {
- seek(getStreamPosition() - 1);
- }
- // Fix 4494976: writeBit(int) does not pad the remainder
- // of the current byte with 0s
- else { // EOF
- partialByte = 0;
- }
-
- int shift = 8 - numBits;
- int mask = -1 >>> (32 - numBits);
- partialByte &= ~(mask << shift);
- partialByte |= (bits & mask) << shift;
- // bitOffset is always already 0 when we get here.
- write(partialByte);
- seek(getStreamPosition() - 1);
- bitOffset = numBits;
- }
- }
-
- /**
- * If the bit offset is non-zero, forces the remaining bits
- * in the current byte to 0 and advances the stream position
- * by one. This method should be called by subclasses at the
- * beginning of the <code>write(int)</code> and
- * <code>write(byte[], int, int)</code> methods.
- *
- * @exception IOException if an I/O error occurs.
- */
- protected final void flushBits() throws IOException {
- checkClosed();
- if (bitOffset != 0) {
- int offset = bitOffset;
- int partialByte = read(); // Sets bitOffset to 0
- if (partialByte < 0) {
- // Fix 4465683: When bitOffset is set
- // to something non-zero beyond EOF,
- // we should set that whole byte to
- // zero and write it to stream.
- partialByte = 0;
- bitOffset = 0;
- }
- else {
- seek(getStreamPosition() - 1);
- partialByte &= -1 << (8 - offset);
- }
- write(partialByte);
- }
- }
-
- }