|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package javax.imageio.stream; |
|
|
|
import java.io.IOException; |
|
import java.io.UTFDataFormatException; |
|
import java.nio.ByteOrder; |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public abstract class ImageOutputStreamImpl |
|
extends ImageInputStreamImpl |
|
implements ImageOutputStream { |
|
|
|
|
|
|
|
*/ |
|
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) { |
|
byteBuf[0] = (byte)(v >>> 8); |
|
byteBuf[1] = (byte)(v >>> 0); |
|
} else { |
|
byteBuf[0] = (byte)(v >>> 0); |
|
byteBuf[1] = (byte)(v >>> 8); |
|
} |
|
write(byteBuf, 0, 2); |
|
} |
|
|
|
public void writeChar(int v) throws IOException { |
|
writeShort(v); |
|
} |
|
|
|
public void writeInt(int v) throws IOException { |
|
if (byteOrder == ByteOrder.BIG_ENDIAN) { |
|
byteBuf[0] = (byte)(v >>> 24); |
|
byteBuf[1] = (byte)(v >>> 16); |
|
byteBuf[2] = (byte)(v >>> 8); |
|
byteBuf[3] = (byte)(v >>> 0); |
|
} else { |
|
byteBuf[0] = (byte)(v >>> 0); |
|
byteBuf[1] = (byte)(v >>> 8); |
|
byteBuf[2] = (byte)(v >>> 16); |
|
byteBuf[3] = (byte)(v >>> 24); |
|
} |
|
write(byteBuf, 0, 4); |
|
} |
|
|
|
public void writeLong(long v) throws IOException { |
|
if (byteOrder == ByteOrder.BIG_ENDIAN) { |
|
byteBuf[0] = (byte)(v >>> 56); |
|
byteBuf[1] = (byte)(v >>> 48); |
|
byteBuf[2] = (byte)(v >>> 40); |
|
byteBuf[3] = (byte)(v >>> 32); |
|
byteBuf[4] = (byte)(v >>> 24); |
|
byteBuf[5] = (byte)(v >>> 16); |
|
byteBuf[6] = (byte)(v >>> 8); |
|
byteBuf[7] = (byte)(v >>> 0); |
|
} else { |
|
byteBuf[0] = (byte)(v >>> 0); |
|
byteBuf[1] = (byte)(v >>> 8); |
|
byteBuf[2] = (byte)(v >>> 16); |
|
byteBuf[3] = (byte)(v >>> 24); |
|
byteBuf[4] = (byte)(v >>> 32); |
|
byteBuf[5] = (byte)(v >>> 40); |
|
byteBuf[6] = (byte)(v >>> 48); |
|
byteBuf[7] = (byte)(v >>> 56); |
|
} |
|
// REMIND: Once 6277756 is fixed, we should do a bulk write of all 8 |
|
// bytes here as we do in writeShort() and writeInt() for even better |
|
// performance. For now, two bulk writes of 4 bytes each is still |
|
|
|
write(byteBuf, 0, 4); |
|
write(byteBuf, 4, 4); |
|
} |
|
|
|
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 { |
|
|
|
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 { |
|
|
|
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 { |
|
|
|
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 { |
|
|
|
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 { |
|
|
|
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 { |
|
|
|
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 |
|
|
|
if ((getStreamPosition() > 0) || (bitOffset > 0)) { |
|
int offset = bitOffset; |
|
int partialByte = read(); |
|
if (partialByte != -1) { |
|
seek(getStreamPosition() - 1); |
|
} else { |
|
partialByte = 0; |
|
} |
|
|
|
if (numBits + offset < 8) { |
|
|
|
int shift = 8 - (offset+numBits); |
|
int mask = -1 >>> (32 - numBits); |
|
partialByte &= ~(mask << shift); |
|
partialByte |= ((bits & mask) << shift); |
|
write(partialByte); |
|
seek(getStreamPosition() - 1); |
|
bitOffset = offset + numBits; |
|
numBits = 0; |
|
} else { |
|
|
|
int num = 8 - offset; |
|
int mask = -1 >>> (32 - num); |
|
partialByte &= ~mask; |
|
partialByte |= ((bits >> (numBits - num)) & mask); |
|
// Note that bitOffset is already 0, so there is no risk |
|
|
|
write(partialByte); |
|
numBits -= num; |
|
} |
|
} |
|
|
|
|
|
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, |
|
|
|
if (numBits != 0) { |
|
// If we are not at the end of the file, read the current byte |
|
|
|
int partialByte = 0; |
|
partialByte = read(); |
|
if (partialByte != -1) { |
|
seek(getStreamPosition() - 1); |
|
} |
|
// Fix 4494976: writeBit(int) does not pad the remainder |
|
|
|
else { |
|
partialByte = 0; |
|
} |
|
|
|
int shift = 8 - numBits; |
|
int mask = -1 >>> (32 - numBits); |
|
partialByte &= ~(mask << shift); |
|
partialByte |= (bits & mask) << shift; |
|
|
|
write(partialByte); |
|
seek(getStreamPosition() - 1); |
|
bitOffset = numBits; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected final void flushBits() throws IOException { |
|
checkClosed(); |
|
if (bitOffset != 0) { |
|
int offset = bitOffset; |
|
int partialByte = read(); |
|
if (partialByte < 0) { |
|
// Fix 4465683: When bitOffset is set |
|
// to something non-zero beyond EOF, |
|
// we should set that whole byte to |
|
|
|
partialByte = 0; |
|
bitOffset = 0; |
|
} |
|
else { |
|
seek(getStreamPosition() - 1); |
|
partialByte &= -1 << (8 - offset); |
|
} |
|
write(partialByte); |
|
} |
|
} |
|
|
|
} |