jogamp.opengl.util.pngj.PngIDatChunkInputStream Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jogl-all Show documentation
Show all versions of jogl-all Show documentation
Java™ Binding for the OpenGL® API
package jogamp.opengl.util.pngj;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.zip.CRC32;
import jogamp.opengl.util.pngj.chunks.ChunkHelper;
/**
* Reads a sequence of contiguous IDAT chunks
*/
class PngIDatChunkInputStream extends InputStream {
private final InputStream inputStream;
private final CRC32 crcEngine;
private boolean checkCrc = true;
private int lenLastChunk;
private byte[] idLastChunk = new byte[4];
private int toReadThisChunk = 0;
private boolean ended = false;
private long offset; // offset inside whole inputstream (counting bytes before IDAT)
// just informational
static class IdatChunkInfo {
public final int len;
public final long offset;
private IdatChunkInfo(int len, long offset) {
this.len = len;
this.offset = offset;
}
}
List foundChunksInfo = new ArrayList();
/**
* Constructor must be called just after reading length and id of first IDAT
* chunk
**/
PngIDatChunkInputStream(InputStream iStream, int lenFirstChunk, long offset) {
this.offset = offset;
inputStream = iStream;
this.lenLastChunk = lenFirstChunk;
toReadThisChunk = lenFirstChunk;
// we know it's a IDAT
System.arraycopy(ChunkHelper.b_IDAT, 0, idLastChunk, 0, 4);
crcEngine = new CRC32();
crcEngine.update(idLastChunk, 0, 4);
foundChunksInfo.add(new IdatChunkInfo(lenLastChunk, offset - 8));
// PngHelper.logdebug("IDAT Initial fragment: len=" + lenLastChunk);
if (this.lenLastChunk == 0)
endChunkGoForNext(); // rare, but...
}
/**
* does NOT close the associated stream!
*/
@Override
public void close() throws IOException {
super.close(); // thsi does nothing
}
private void endChunkGoForNext() {
// Called after readging the last byte of one IDAT chunk
// Checks CRC, and read ID from next CHUNK
// Those values are left in idLastChunk / lenLastChunk
// Skips empty IDATS
do {
int crc = PngHelperInternal.readInt4(inputStream); //
offset += 4;
if (checkCrc) {
int crccalc = (int) crcEngine.getValue();
if (lenLastChunk > 0 && crc != crccalc)
throw new PngjBadCrcException("error reading idat; offset: " + offset);
crcEngine.reset();
}
lenLastChunk = PngHelperInternal.readInt4(inputStream);
toReadThisChunk = lenLastChunk;
PngHelperInternal.readBytes(inputStream, idLastChunk, 0, 4);
offset += 8;
// found a NON IDAT chunk? this stream is ended
ended = !Arrays.equals(idLastChunk, ChunkHelper.b_IDAT);
if (!ended) {
foundChunksInfo.add(new IdatChunkInfo(lenLastChunk, offset - 8));
if (checkCrc)
crcEngine.update(idLastChunk, 0, 4);
}
// PngHelper.logdebug("IDAT ended. next len= " + lenLastChunk + " idat?" +
// (!ended));
} while (lenLastChunk == 0 && !ended);
// rarely condition is true (empty IDAT ??)
}
/**
* sometimes last row read does not fully consumes the chunk here we read
* the reamaing dummy bytes
*/
void forceChunkEnd() {
if (!ended) {
byte[] dummy = new byte[toReadThisChunk];
PngHelperInternal.readBytes(inputStream, dummy, 0, toReadThisChunk);
if (checkCrc)
crcEngine.update(dummy, 0, toReadThisChunk);
endChunkGoForNext();
}
}
/**
* This can return less than len, but never 0 Returns -1 if "pseudo file"
* ended prematurely. That is our error.
*/
@Override
public int read(byte[] b, int off, int len) throws IOException {
if (ended)
return -1; // can happen only when raw reading, see Pngreader.readAndSkipsAllRows()
if (toReadThisChunk == 0)
throw new PngjExceptionInternal("this should not happen");
int n = inputStream.read(b, off, len >= toReadThisChunk ? toReadThisChunk : len);
if (n > 0) {
if (checkCrc)
crcEngine.update(b, off, n);
this.offset += n;
toReadThisChunk -= n;
}
if (toReadThisChunk == 0) { // end of chunk: prepare for next
endChunkGoForNext();
}
return n;
}
@Override
public int read(byte[] b) throws IOException {
return this.read(b, 0, b.length);
}
@Override
public int read() throws IOException {
// PngHelper.logdebug("read() should go here");
// inneficient - but this should be used rarely
byte[] b1 = new byte[1];
int r = this.read(b1, 0, 1);
return r < 0 ? -1 : (int) b1[0];
}
int getLenLastChunk() {
return lenLastChunk;
}
byte[] getIdLastChunk() {
return idLastChunk;
}
long getOffset() {
return offset;
}
boolean isEnded() {
return ended;
}
/**
* Disables CRC checking. This can make reading faster
*/
void disableCrcCheck() {
checkCrc = false;
}
}