diff options
Diffstat (limited to 'src/jogl/classes/jogamp/opengl/util/pngj/PngIDatChunkInputStream.java')
-rw-r--r-- | src/jogl/classes/jogamp/opengl/util/pngj/PngIDatChunkInputStream.java | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/src/jogl/classes/jogamp/opengl/util/pngj/PngIDatChunkInputStream.java b/src/jogl/classes/jogamp/opengl/util/pngj/PngIDatChunkInputStream.java new file mode 100644 index 000000000..66c4b49f0 --- /dev/null +++ b/src/jogl/classes/jogamp/opengl/util/pngj/PngIDatChunkInputStream.java @@ -0,0 +1,153 @@ +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 IDAT chunks
+ */
+class PngIDatChunkInputStream extends InputStream {
+ private final InputStream inputStream;
+ private final CRC32 crcEngine;
+ private int lenLastChunk;
+ private byte[] idLastChunk = new byte[4];
+ private int toReadThisChunk = 0;
+ private boolean ended = false;
+ private long offset; // offset inside inputstream
+
+ // just informational
+ static class IdatChunkInfo {
+ public final int len;
+ public final int offset;
+
+ private IdatChunkInfo(int len, int offset) {
+ this.len = len;
+ this.offset = offset;
+ }
+ }
+
+ List<IdatChunkInfo> foundChunksInfo = new ArrayList<IdatChunkInfo>();
+
+ /**
+ * Constructor must be called just after reading length and id of first IDAT chunk
+ **/
+ PngIDatChunkInputStream(InputStream iStream, int lenFirstChunk, int offset) {
+ this.offset = (long) offset;
+ inputStream = iStream;
+ crcEngine = new CRC32();
+ this.lenLastChunk = lenFirstChunk;
+ toReadThisChunk = lenFirstChunk;
+ // we know it's a IDAT
+ System.arraycopy(ChunkHelper.b_IDAT, 0, idLastChunk, 0, 4);
+ 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(); // nothing
+ }
+
+ private void endChunkGoForNext() {
+ // Called after readging the last byte of chunk
+ // Checks CRC, and read ID from next CHUNK
+ // Those values are left in idLastChunk / lenLastChunk
+ // Skips empty IDATS
+ do {
+ int crc = PngHelper.readInt4(inputStream); //
+ offset += 4;
+ int crccalc = (int) crcEngine.getValue();
+ if (lenLastChunk > 0 && crc != crccalc)
+ throw new PngjBadCrcException("error reading idat; offset: " + offset);
+ crcEngine.reset();
+ lenLastChunk = PngHelper.readInt4(inputStream);
+ if (lenLastChunk < 0)
+ throw new PngjInputException("invalid len for chunk: " + lenLastChunk);
+ toReadThisChunk = lenLastChunk;
+ PngHelper.readBytes(inputStream, idLastChunk, 0, 4);
+ offset += 8;
+ ended = !Arrays.equals(idLastChunk, ChunkHelper.b_IDAT);
+ if (!ended) {
+ foundChunksInfo.add(new IdatChunkInfo(lenLastChunk, (int) (offset - 8)));
+ 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];
+ PngHelper.readBytes(inputStream, dummy, 0, toReadThisChunk);
+ 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 (toReadThisChunk == 0)
+ throw new RuntimeException("this should not happen");
+ int n = inputStream.read(b, off, len >= toReadThisChunk ? toReadThisChunk : len);
+ if (n > 0) {
+ 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;
+ }
+}
|