ch.randelshofer.io.ByteArrayImageInputStream Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aem-sdk-api Show documentation
Show all versions of aem-sdk-api Show documentation
The Adobe Experience Manager SDK
/*
* @(#)ByteArrayImageInputStream.java 1.0 2008-10-18
*
* Copyright (c) 2008 Werner Randelshofer, Immensee, Switzerland.
* All rights reserved.
*
* You may not use, copy or modify this file, except in compliance with the
* license agreement you entered into with Werner Randelshofer.
* For details see accompanying license terms.
*/
package ch.randelshofer.io;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.nio.ByteOrder;
import java.util.Stack;
import javax.imageio.stream.IIOByteBuffer;
import javax.imageio.stream.ImageInputStream;
/**
* ByteArrayImageInputStream.
*
* @author Werner Randelshofer, Hausmatt 10, CH-6405 Immensee
* @version 1.0 2008-10-18 Created.
*/
public class ByteArrayImageInputStream extends ByteArrayInputStream implements ImageInputStream {
/**
* The byte order of the stream as an instance of the enumeration
* class java.nio.ByteOrder
, where
* ByteOrder.BIG_ENDIAN
indicates network byte order
* and ByteOrder.LITTLE_ENDIAN
indicates the reverse
* order. By default, the value is
* ByteOrder.BIG_ENDIAN
.
*/
protected ByteOrder byteOrder = ByteOrder.BIG_ENDIAN;
/**
* The current bit offset within the stream. Subclasses are
* responsible for keeping this value current from any method they
* override that alters the bit offset.
*/
protected int bitOffset;
/** Length of the buffer used for readFully(type[], int, int) */
private static final int BYTE_BUF_LENGTH = 8192;
/** Byte buffer used for readFully(type[], int, int) */
private byte[] byteBuf = new byte[BYTE_BUF_LENGTH];
/** The last flushed positione. */
private long flushedPos;
private static class Marker {
private int bytePos, bitPos;
public Marker(int bytePos, int bitPos) {
this.bytePos=bytePos;
this.bitPos=bitPos;
}
};
/** Marked bit and byte positions. */
private Stack markStack = new Stack();
/** The offset of the input stream in the underlying byte array. */
private int arrayOffset;
public ByteArrayImageInputStream(byte[] buf) {
this(buf, ByteOrder.BIG_ENDIAN);
}
public ByteArrayImageInputStream(byte[] buf, ByteOrder byteOrder) {
this(buf, 0, buf.length, byteOrder);
}
public ByteArrayImageInputStream(byte[] buf, int offset, int length, ByteOrder byteOrder) {
super(buf, offset, length);
arrayOffset = offset;
this.byteOrder = byteOrder;
}
// @Override
public void setByteOrder(ByteOrder byteOrder) {
this.byteOrder = byteOrder;
}
// @Override
public ByteOrder getByteOrder() {
return byteOrder;
}
// @Override
public void readBytes(IIOByteBuffer buf, int len) throws IOException {
if (len < 0) {
throw new IndexOutOfBoundsException("len < 0!");
}
if (buf == null) {
throw new NullPointerException("buf == null!");
}
byte[] data = new byte[len];
len = read(data, 0, len);
buf.setData(data);
buf.setOffset(0);
buf.setLength(len);
}
// @Override
public boolean readBoolean() throws IOException {
int ch = this.read();
if (ch < 0) {
throw new EOFException();
}
return (ch != 0);
}
// @Override
public byte readByte() throws IOException {
int ch = this.read();
if (ch < 0) {
throw new EOFException();
}
return (byte) ch;
}
// @Override
public int readUnsignedByte() throws IOException {
int ch = this.read();
if (ch < 0) {
throw new EOFException();
}
return ch;
}
// @Override
public short readShort() throws IOException {
int ch1 = this.read();
int ch2 = this.read();
if ((ch1 | ch2) < 0) {
throw new EOFException();
}
if (byteOrder == ByteOrder.BIG_ENDIAN) {
return (short) ((ch1 << 8) + (ch2 << 0));
} else {
return (short) ((ch2 << 8) + (ch1 << 0));
}
}
// @Override
public int readUnsignedShort() throws IOException {
return (readShort()) & 0xffff;
}
// @Override
public char readChar() throws IOException {
return (char) readShort();
}
// @Override
public int readInt() throws IOException {
int ch1 = this.read();
int ch2 = this.read();
int ch3 = this.read();
int ch4 = this.read();
if ((ch1 | ch2 | ch3 | ch4) < 0) {
throw new EOFException();
}
if (byteOrder == ByteOrder.BIG_ENDIAN) {
return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
} else {
return ((ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0));
}
}
// @Override
public long readUnsignedInt() throws IOException {
return (readInt()) & 0xffffffffL;
}
// @Override
public long readLong() throws IOException {
int i1 = readInt();
int i2 = readInt();
if (byteOrder == ByteOrder.BIG_ENDIAN) {
return ((long) i1 << 32) + (i2 & 0xFFFFFFFFL);
} else {
return ((long) i2 << 32) + (i1 & 0xFFFFFFFFL);
}
}
// @Override
public float readFloat() throws IOException {
return Float.intBitsToFloat(readInt());
}
// @Override
public double readDouble() throws IOException {
return Double.longBitsToDouble(readLong());
}
// @Override
public String readLine() throws IOException {
StringBuffer input = new StringBuffer();
int c = -1;
boolean eol = false;
while (!eol) {
switch (c = read()) {
case -1:
case '\n':
eol = true;
break;
case '\r':
eol = true;
long cur = getStreamPosition();
if ((read()) != '\n') {
seek(cur);
}
break;
default:
input.append((char) c);
break;
}
}
if ((c == -1) && (input.length() == 0)) {
return null;
}
return input.toString();
}
// @Override
public String readUTF() throws IOException {
this.bitOffset = 0;
// Fix 4494369: method ImageInputStreamImpl.readUTF()
// does not work as specified (it should always assume
// network byte order).
ByteOrder oldByteOrder = getByteOrder();
setByteOrder(ByteOrder.BIG_ENDIAN);
String ret;
try {
ret = DataInputStream.readUTF(this);
} catch (IOException e) {
// Restore the old byte order even if an exception occurs
setByteOrder(oldByteOrder);
throw e;
}
setByteOrder(oldByteOrder);
return ret;
}
// @Override
public void readFully(byte[] b, int off, int len) throws IOException {
// Fix 4430357 - if off + len < 0, overflow occurred
if (off < 0 || len < 0 || off + len > b.length || off + len < 0) {
throw new IndexOutOfBoundsException("off < 0 || len < 0 || off + len > b.length!");
}
while (len > 0) {
int nbytes = read(b, off, len);
if (nbytes == -1) {
throw new EOFException();
}
off += nbytes;
len -= nbytes;
}
}
// @Override
public void readFully(byte[] b) throws IOException {
readFully(b, 0, b.length);
}
// @Override
public void readFully(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!");
}
while (len > 0) {
int nelts = Math.min(len, byteBuf.length / 2);
readFully(byteBuf, 0, nelts * 2);
toShorts(byteBuf, s, off, nelts);
off += nelts;
len -= nelts;
}
}
// @Override
public void readFully(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!");
}
while (len > 0) {
int nelts = Math.min(len, byteBuf.length / 2);
readFully(byteBuf, 0, nelts * 2);
toChars(byteBuf, c, off, nelts);
off += nelts;
len -= nelts;
}
}
// @Override
public void readFully(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!");
}
while (len > 0) {
int nelts = Math.min(len, byteBuf.length / 4);
readFully(byteBuf, 0, nelts * 4);
toInts(byteBuf, i, off, nelts);
off += nelts;
len -= nelts;
}
}
// @Override
public void readFully(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!");
}
while (len > 0) {
int nelts = Math.min(len, byteBuf.length / 8);
readFully(byteBuf, 0, nelts * 8);
toLongs(byteBuf, l, off, nelts);
off += nelts;
len -= nelts;
}
}
// @Override
public void readFully(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!");
}
while (len > 0) {
int nelts = Math.min(len, byteBuf.length / 4);
readFully(byteBuf, 0, nelts * 4);
toFloats(byteBuf, f, off, nelts);
off += nelts;
len -= nelts;
}
}
// @Override
public void readFully(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!");
}
while (len > 0) {
int nelts = Math.min(len, byteBuf.length / 8);
readFully(byteBuf, 0, nelts * 8);
toDoubles(byteBuf, d, off, nelts);
off += nelts;
len -= nelts;
}
}
private void toShorts(byte[] b, short[] s, int off, int len) {
int boff = 0;
if (byteOrder == ByteOrder.BIG_ENDIAN) {
for (int j = 0; j < len; j++) {
int b0 = b[boff];
int b1 = b[boff + 1] & 0xff;
s[off + j] = (short) ((b0 << 8) | b1);
boff += 2;
}
} else {
for (int j = 0; j < len; j++) {
int b0 = b[boff + 1];
int b1 = b[boff] & 0xff;
s[off + j] = (short) ((b0 << 8) | b1);
boff += 2;
}
}
}
private void toChars(byte[] b, char[] c, int off, int len) {
int boff = 0;
if (byteOrder == ByteOrder.BIG_ENDIAN) {
for (int j = 0; j < len; j++) {
int b0 = b[boff];
int b1 = b[boff + 1] & 0xff;
c[off + j] = (char) ((b0 << 8) | b1);
boff += 2;
}
} else {
for (int j = 0; j < len; j++) {
int b0 = b[boff + 1];
int b1 = b[boff] & 0xff;
c[off + j] = (char) ((b0 << 8) | b1);
boff += 2;
}
}
}
private void toInts(byte[] b, int[] i, int off, int len) {
int boff = 0;
if (byteOrder == ByteOrder.BIG_ENDIAN) {
for (int j = 0; j < len; j++) {
int b0 = b[boff];
int b1 = b[boff + 1] & 0xff;
int b2 = b[boff + 2] & 0xff;
int b3 = b[boff + 3] & 0xff;
i[off + j] = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
boff += 4;
}
} else {
for (int j = 0; j < len; j++) {
int b0 = b[boff + 3];
int b1 = b[boff + 2] & 0xff;
int b2 = b[boff + 1] & 0xff;
int b3 = b[boff] & 0xff;
i[off + j] = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
boff += 4;
}
}
}
private void toLongs(byte[] b, long[] l, int off, int len) {
int boff = 0;
if (byteOrder == ByteOrder.BIG_ENDIAN) {
for (int j = 0; j < len; j++) {
int b0 = b[boff];
int b1 = b[boff + 1] & 0xff;
int b2 = b[boff + 2] & 0xff;
int b3 = b[boff + 3] & 0xff;
int b4 = b[boff + 4];
int b5 = b[boff + 5] & 0xff;
int b6 = b[boff + 6] & 0xff;
int b7 = b[boff + 7] & 0xff;
int i0 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
int i1 = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
l[off + j] = ((long) i0 << 32) | (i1 & 0xffffffffL);
boff += 8;
}
} else {
for (int j = 0; j < len; j++) {
int b0 = b[boff + 7];
int b1 = b[boff + 6] & 0xff;
int b2 = b[boff + 5] & 0xff;
int b3 = b[boff + 4] & 0xff;
int b4 = b[boff + 3];
int b5 = b[boff + 2] & 0xff;
int b6 = b[boff + 1] & 0xff;
int b7 = b[boff] & 0xff;
int i0 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
int i1 = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
l[off + j] = ((long) i0 << 32) | (i1 & 0xffffffffL);
boff += 8;
}
}
}
private void toFloats(byte[] b, float[] f, int off, int len) {
int boff = 0;
if (byteOrder == ByteOrder.BIG_ENDIAN) {
for (int j = 0; j < len; j++) {
int b0 = b[boff];
int b1 = b[boff + 1] & 0xff;
int b2 = b[boff + 2] & 0xff;
int b3 = b[boff + 3] & 0xff;
int i = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
f[off + j] = Float.intBitsToFloat(i);
boff += 4;
}
} else {
for (int j = 0; j < len; j++) {
int b0 = b[boff + 3];
int b1 = b[boff + 2] & 0xff;
int b2 = b[boff + 1] & 0xff;
int b3 = b[boff + 0] & 0xff;
int i = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
f[off + j] = Float.intBitsToFloat(i);
boff += 4;
}
}
}
private void toDoubles(byte[] b, double[] d, int off, int len) {
int boff = 0;
if (byteOrder == ByteOrder.BIG_ENDIAN) {
for (int j = 0; j < len; j++) {
int b0 = b[boff];
int b1 = b[boff + 1] & 0xff;
int b2 = b[boff + 2] & 0xff;
int b3 = b[boff + 3] & 0xff;
int b4 = b[boff + 4];
int b5 = b[boff + 5] & 0xff;
int b6 = b[boff + 6] & 0xff;
int b7 = b[boff + 7] & 0xff;
int i0 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
int i1 = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
long l = ((long) i0 << 32) | (i1 & 0xffffffffL);
d[off + j] = Double.longBitsToDouble(l);
boff += 8;
}
} else {
for (int j = 0; j < len; j++) {
int b0 = b[boff + 7];
int b1 = b[boff + 6] & 0xff;
int b2 = b[boff + 5] & 0xff;
int b3 = b[boff + 4] & 0xff;
int b4 = b[boff + 3];
int b5 = b[boff + 2] & 0xff;
int b6 = b[boff + 1] & 0xff;
int b7 = b[boff] & 0xff;
int i0 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
int i1 = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
long l = ((long) i0 << 32) | (i1 & 0xffffffffL);
d[off + j] = Double.longBitsToDouble(l);
boff += 8;
}
}
}
// @Override
public long getStreamPosition() {
checkClosed();
return pos - arrayOffset;
}
// @Override
public int getBitOffset() {
checkClosed();
return bitOffset;
}
// @Override
public void setBitOffset(int bitOffset) {
checkClosed();
if (bitOffset < 0 || bitOffset > 7) {
throw new IllegalArgumentException("bitOffset must be betwwen 0 and 7!");
}
this.bitOffset = bitOffset;
}
// @Override
public int readBit() throws IOException {
checkClosed();
// Compute final bit offset before we call read() and seek()
int newBitOffset = (this.bitOffset + 1) & 0x7;
int val = read();
if (val == -1) {
throw new EOFException();
}
if (newBitOffset != 0) {
// Move byte position back if in the middle of a byte
seek(getStreamPosition() - 1);
// Shift the bit to be read to the rightmost position
val >>= 8 - newBitOffset;
}
this.bitOffset = newBitOffset;
return val & 0x1;
}
// @Override
public long readBits(int numBits) throws IOException {
checkClosed();
if (numBits < 0 || numBits > 64) {
throw new IllegalArgumentException();
}
if (numBits == 0) {
return 0L;
}
// Have to read additional bits on the left equal to the bit offset
int bitsToRead = numBits + bitOffset;
// Compute final bit offset before we call read() and seek()
int newBitOffset = (this.bitOffset + numBits) & 0x7;
// Read a byte at a time, accumulate
long accum = 0L;
while (bitsToRead > 0) {
int val = read();
if (val == -1) {
throw new EOFException();
}
accum <<= 8;
accum |= val;
bitsToRead -= 8;
}
// Move byte position back if in the middle of a byte
if (newBitOffset != 0) {
seek(getStreamPosition() - 1);
}
this.bitOffset = newBitOffset;
// Shift away unwanted bits on the right.
accum >>>= (-bitsToRead); // Negative of bitsToRead == extra bits read
// Mask out unwanted bits on the left
accum &= (-1L >>> (64 - numBits));
return accum;
}
// @Override
public long length() throws IOException {
return count;
}
// @Override
public int skipBytes(int n) throws IOException {
long pos = getStreamPosition();
seek(pos + n);
return (int) (getStreamPosition() - pos);
}
// @Override
public long skipBytes(long n) throws IOException {
long pos = getStreamPosition();
seek(pos + n);
return (int) (getStreamPosition() - pos);
}
// @Override
public void seek(long pos) throws IOException {
if (pos < 0) {
throw new IndexOutOfBoundsException("pos < 0!");
}
this.pos = (int) pos + arrayOffset;
this.bitOffset = 0;
}
// @Override
public void flushBefore(long pos) throws IOException {
if (pos < flushedPos) {
throw new IndexOutOfBoundsException("pos < flushedPos!");
}
if (pos > getStreamPosition()) {
throw new IndexOutOfBoundsException("pos > getStreamPosition()!");
}
// Invariant: flushedPos >= 0
flushedPos = pos + arrayOffset;
}
// @Override
public void flush() throws IOException {
flushBefore(pos);
}
// @Override
public long getFlushedPosition() {
return flushedPos;
}
// @Override
public boolean isCached() {
return true;
}
// @Override
public boolean isCachedMemory() {
return true;
}
// @Override
public boolean isCachedFile() {
return false;
}
private void checkClosed() {
// nothing to do
}
// @Override
public void mark() {
markStack.push(new Marker(pos, bitOffset));
}
@Override
public void reset() {
if (markStack.empty()) {
return;
}
Marker marker = markStack.pop();
if (marker.bytePos < flushedPos) {
throw new InternalError("Previous marked position has been discarded!");
}
pos=marker.bytePos;
setBitOffset(marker.bitPos);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy