private static int Codes(BitStream bitStream, Huffman lencode, Huffman distcode, bool lastBlock) { int symbol; do { symbol = Decode(bitStream, lencode); if (symbol < 0) { throw new ArgumentOutOfRangeException("invalid symbol."); } if (symbol < 256) { bitStream.OutBuffer.Add((byte)symbol); //bitStream.OutBufferWithHeader.Add((byte)symbol); //if (bitStream.OutBuffer.Count() % 65535 == 0) //{ // Console.WriteLine("blocked"); // var blocks = bitStream.OutBuffer.Count() / 65535; // bitStream.OutBufferWithHeader.InsertRange((65535 + 5) * (blocks - 1), BlockHeader(65535, false)); //} } else if (symbol > 256) { symbol -= 257; if (symbol >= 29) { throw new Exception("Invalid fixed code."); } var len = lens[symbol] + bitStream.GetNextBitsReverse(lext[symbol]); symbol = Decode(bitStream, distcode); if (symbol < 0) { throw new ArgumentOutOfRangeException("invalid symbol."); } var dist = dists[symbol] + bitStream.GetNextBitsReverse(dext[symbol]); // copy length bytes from distance bytes back. for (int i = 0; i < len; i++) { bitStream.OutBuffer.Add(bitStream.OutBuffer[bitStream.OutBuffer.Count() - dist]); //bitStream.OutBufferWithHeader.Add(bitStream.OutBuffer[bitStream.OutBuffer.Count() - dist]); //if (bitStream.OutBuffer.Count() % 65535 == 0) //{ // Console.WriteLine("blocked"); // var blocks = bitStream.OutBuffer.Count() / 65535; // bitStream.OutBufferWithHeader.InsertRange((65535 + 5) * (blocks - 1), BlockHeader(65535, false)); //} } } } while (symbol != 256); //if (lastBlock) //{ // var blocks = bitStream.OutBuffer.Count() / 65535; // bitStream.OutBufferWithHeader.InsertRange((65535 + 5) * (blocks - 1), BlockHeader((ushort)(bitStream.OutBuffer.Count() % 65535), true)); //} return(0); }
static void Decode(ref PNG png) { Console.WriteLine($"\nDecoding zlib blocks..."); Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); uint idatLength = 0; foreach (var chunk in png.IDATList) { idatLength += chunk.ChunkLength; } byte[] idatData = new byte[idatLength]; var offset = 0; for (int i = 0; i < png.IDATList.Count(); i++) { Array.Copy(png.IDATList[i].ChunkData, 0, idatData, offset, (int)png.IDATList[i].ChunkLength); offset += (int)png.IDATList[i].ChunkLength; } Stream idatStream = new MemoryStream(idatData); var zlibHeader = new byte[2]; idatStream.Read(zlibHeader, 0, 2); var bitBuffer = new byte[idatLength - 6]; // subtract 2 byte zlib header and 4 byte adler checksum. idatStream.Read(bitBuffer, 0, (int)(idatLength - 6)); idatStream.Dispose(); BitArray bitArray = new BitArray(bitBuffer); BitStream bs = new BitStream(bitArray); bool lastBlock; byte compression; do { lastBlock = bs.GetNextBitsReverse(1) == 1; compression = (byte)bs.GetNextBitsReverse(2); if (compression == 0) { Console.WriteLine($"Zlib block already uncompressed..."); bs.GetNextBitsReverse(5); ushort len = bs.GetNextShortReverse(); ushort nen = (ushort)~bs.GetNextShortReverse(); if (nen != len) { throw new Exception("Nen does not complement Len."); } for (int i = 0; i < len; i++) { bs.GetNextBitsReverse(8); } } else if (compression == 1) { Console.WriteLine($"Uncompressing {(lastBlock ? "last " : "")}zlib block..."); Puff.ParseFixed(bs, lastBlock); } else if (compression == 2) { Console.WriteLine($"Uncompressing {(lastBlock ? "last " : "")}zlib block..."); Puff.ParseDynamic(bs, lastBlock); } }while (lastBlock == false); if (compression != 0) { var adler = new Adler32(); adler.Update(bs.OutBuffer.ToArray()); byte[] adlerbytearray = BitConverter.GetBytes((int)adler.Value); Array.Reverse(adlerbytearray, 0, adlerbytearray.Length); Console.WriteLine($"Adler32 checksum = {adlerbytearray[0]} {adlerbytearray[1]} {adlerbytearray[2]} {adlerbytearray[3]}"); var numblocks = (bs.OutBuffer.Count()) / 65500; var numblocksRem = (bs.OutBuffer.Count()) % 65500; var splitBlocklist = new List <byte>(); if (numblocks > 0) { for (int j = 0; j < numblocks; j++) { InsertBlockHeader(splitBlocklist, 65500, false); for (int i = 0; i < 65500; i++) { splitBlocklist.Add(bs.OutBuffer[i + j * 65500]); } } InsertBlockHeader(splitBlocklist, (ushort)numblocksRem, true); for (int i = (int)(bs.OutBuffer.Count() - numblocksRem); i < (bs.OutBuffer.Count()); i++) { splitBlocklist.Add(bs.OutBuffer[i]); } } else { InsertBlockHeader(splitBlocklist, (ushort)numblocksRem, true); for (int i = (int)(bs.OutBuffer.Count() - numblocksRem); i < (bs.OutBuffer.Count()); i++) { splitBlocklist.Add(bs.OutBuffer[i]); } } for (int i = 0; i < adlerbytearray.Length; i++) { splitBlocklist.Add(adlerbytearray[i]); } byte[] newChunkData = new byte[splitBlocklist.Count() + 2]; zlibHeader.CopyTo(newChunkData, 0); splitBlocklist.ToArray().CopyTo(newChunkData, 2); var ncdChunks = newChunkData.Length / 65500; var ncdRem = newChunkData.Length % 65500; png.IDATList.Clear(); for (int i = 0; i < ncdChunks; i++) { IDATChunk newIdatChunk = new IDATChunk(); newIdatChunk.ChunkData = newChunkData.SubArray(i * 65500, 65500); png.IDATList.Add(newIdatChunk); } IDATChunk finalIdatChunk = new IDATChunk(); finalIdatChunk.ChunkData = newChunkData.SubArray(newChunkData.Length - ncdRem, ncdRem); png.IDATList.Add(finalIdatChunk); } stopWatch.Stop(); string elapsedTime = stopWatch.Elapsed.FormatTime(); Console.WriteLine($"Total decode time = {elapsedTime}"); }
public static int ParseDynamic(BitStream bitStream, bool lastBlock) { short[] lengths = new short[MAXCODES]; int nlen = bitStream.GetNextBitsReverse(5) + 257; int ndist = bitStream.GetNextBitsReverse(5) + 1; int ncode = bitStream.GetNextBitsReverse(4) + 4; if (nlen > MAXLCODES || ndist > MAXDCODES) { throw new Exception("bad counts"); } for (int i = 0; i < ncode; i++) { lengths[order[i]] = (short)bitStream.GetNextBitsReverse(3); } for (int i = ncode; i < 19; i++) { lengths[order[i]] = 0; } //for (int i = 0; i < lengths.Length; i++) //{ // Console.WriteLine($"symbol {i} has a code length of {lengths[i]}"); //} var lencode = new Huffman(new short[MAXBITS + 1], new short[MAXLCODES]); var distcode = new Huffman(new short[MAXBITS + 1], new short[MAXDCODES]); var err = Construct(ref lencode, lengths, 19); if (err != 0) { throw new Exception("complete code set required here; code lengths codes incomplete."); } //for (int i = 0; i < lencode.count.Length; i++) //{ // Console.WriteLine($"{lencode.count[i]} symbols of length {i}"); //} var index = 0; while (index < nlen + ndist) { var symbol = Decode(bitStream, lencode); var len = 0; if (symbol < 0) { throw new ArgumentOutOfRangeException("invalid symbol"); } if (symbol < 16) { lengths[index++] = (short)symbol; } else { if (symbol == 16) { if (index == 0) { throw new ArgumentOutOfRangeException("no preceeding length to reference!"); } len = lengths[index - 1]; symbol = 3 + bitStream.GetNextBitsReverse(2); } else if (symbol == 17) { symbol = 3 + bitStream.GetNextBitsReverse(3); } else { symbol = 11 + bitStream.GetNextBitsReverse(7); } if (index + symbol > nlen + ndist) { throw new ArgumentOutOfRangeException("too many lengths!"); } while (symbol-- > 0) { lengths[index++] = (short)len; } } } if (lengths[256] == 0) { throw new Exception("no end of block code"); } err = Construct(ref lencode, lengths, nlen); if (err != 0 & (err < 0 || nlen != lencode.count[0] + lencode.count[1])) { throw new ArgumentException("incomplete code ok only for single length 1 code."); } var _lengths = new short[MAXDCODES]; Array.Copy(lengths, nlen, _lengths, 0, MAXDCODES); err = Construct(ref distcode, _lengths, ndist); if (err != 0 & (err < 0 || nlen != distcode.count[0] + distcode.count[1])) { throw new ArgumentException("incomplete code ok only for single length 1 code."); } return(Codes(bitStream, lencode, distcode, lastBlock)); }