/*
* Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package javax.imageio.stream;
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.
*
*/
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) {
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
// faster than 8 individual write() calls (see 6347575 for details).
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 {
// 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);
}
}
}