package ar.com.hjg.pngj; import ar.com.hjg.pngj.chunks.PngChunkFDAT; /** * * Specialization of ChunkReader, for IDAT-like chunks. These chunks are part of * a set of similar chunks (contiguos * normally, not necessariyl) which conforms a zlib stream */ public class DeflatedChunkReader extends ChunkReader { protected final DeflatedChunksSet deflatedChunksSet; protected boolean alsoBuffer = false; protected boolean skipBytes = false; // fDAT (APNG) skips 4 bytes) protected byte[] skippedBytes; // only for fDAT protected int seqNumExpected = -1; // only for fDAT public DeflatedChunkReader(final int clen, final String chunkid, final boolean checkCrc, final long offsetInPng, final DeflatedChunksSet iDatSet) { super(clen, chunkid, offsetInPng, ChunkReaderMode.PROCESS); deflatedChunksSet = iDatSet; if (chunkid.equals(PngChunkFDAT.ID)) { skipBytes = true; skippedBytes = new byte[4]; } iDatSet.appendNewChunk(this); } /** * Delegates to ChunkReaderDeflatedSet.processData() */ @Override protected void processData(final int offsetInchunk, final byte[] buf, int off, int len) { if (skipBytes && offsetInchunk < 4) for (int oc = offsetInchunk; oc < 4 && len > 0; oc++, off++, len--) skippedBytes[oc] = buf[off]; if (len > 0) { // delegate to idatSet deflatedChunksSet.processBytes(buf, off, len); if (alsoBuffer) System.arraycopy(buf, off, getChunkRaw().data, read, len); } } /** * only a stupid check for fDAT (I wonder how many APGN readers do this) */ @Override protected void chunkDone() { if (skipBytes && getChunkRaw().id.equals(PngChunkFDAT.ID)) if (seqNumExpected >= 0) { final int seqNum = PngHelperInternal.readInt4fromBytes(skippedBytes, 0); if (seqNum != seqNumExpected) throw new PngjInputException("bad chunk sequence for fDAT chunk " + seqNum + " expected " + seqNumExpected); } } @Override public boolean isFromDeflatedSet() { return true; } /** * In some rare cases you might want to also buffer the data? */ public void setAlsoBuffer() { if (read > 0) throw new RuntimeException("too late"); alsoBuffer = true; getChunkRaw().allocData(); } /** only relevant for fDAT */ public void setSeqNumExpected(final int seqNumExpected) { this.seqNumExpected = seqNumExpected; } }