Search code examples
c++pngzlib

Zlib Inflation stream not set to Z_STREAM_END at end of PNG IDAT data


I am trying to write my own PNG decoder for learning purposes. The code I'm using to decompress the data is below:

//Stores the return code from the inflation stream
int returnCode;

//Tracks amount of data inflated
unsigned int dataReturned;

//Inflation stream
z_stream stream;

//Initalising the inflation state
stream.zalloc = Z_NULL;
stream.zfree = Z_NULL;
stream.opaque = Z_NULL;
stream.avail_in = chunkSize;
stream.next_in = compressedPixelData;

//Beginning the inflation stream

cout << "Beginning inflation" << endl;
returnCode = inflateInit(&stream);

//Checks for any errors with the inflation stream
if (returnCode != Z_OK)
    throw invalid_argument("Provided file is corrupted or does not use deflate as its compression algorithm");

//Pointing the stream to the output array
stream.avail_out = chunkSize;
stream.next_out = pixelData;

//Inflating the data
returnCode = inflate(&stream, Z_NO_FLUSH);

//Checking for errors
switch (returnCode) {

case Z_NEED_DICT:
case Z_DATA_ERROR:
case Z_MEM_ERROR:
    throw runtime_error("Error while decompressing pixel data. Either out of memory or the file is corrupted.");

}

dataReturned = chunkSize - stream.avail_out;
cout << dataReturned << endl;

//Ending the deflation stream and cleaning up

cout << "Return Code: " << returnCode << endl;
(void)inflateEnd(&stream);
delete[] compressedPixelData;

I get Z_OK as the return code at the end of inflating the chunk. I've double checked and there is only one IDAT chunk in the file, chunkSize is the size of the chunk taken from the header of the chunk, and both compressedPixelData and pixelData are both char arrays allocated with chunkSize bytes of memory. pixelData contains the entire contents of the IDAT chunk (excluding the CRC checksum).

Why is the return code still Z_OK instead of Z_STREAM_END, once the entire IDAT chunk has been inflated?


Solution

  • As pointed out by Shawn, the decompressed data is larger than the original input data. Increasing the size of stream.avali_out and the output buffer, pixelData fixed the issue.