1
votes

When I attempt to decompress data of a size greater than 2048 the zlib uncompress call returns Z_OK. So to clarify if I decompress data of size 2980 it will decompress upto 2048 (Two loops) and then return Z_OK. What am i missing?

Bytes is a vector< unsigned char >;

   Bytes uncompressIt( const Bytes& data )
   {
       size_t buffer_length = 1024;

       Byte* buffer = nullptr;

       int status = 0;

       do
       {
           buffer = ( Byte* ) calloc( buffer_length + 1, sizeof( Byte ) );

           int status = uncompress( buffer, &buffer_length, &data[ 0 ], data.size( ) );  

           if ( status == Z_OK )
           {
              break;
           }
           else if ( status == Z_MEM_ERROR )
           {
              throw runtime_error( "GZip decompress ran out of memory." );
           }
           else if ( status == Z_DATA_ERROR )
           {
              throw runtime_error( "GZip decompress input data was corrupted or incomplete." );
           }
           else //if ( status == Z_BUF_ERROR )
           {
              free( buffer );

              buffer_length *= 2;
           }
       } while ( status == Z_BUF_ERROR ); //then the output buffer wasn't large enough

       Bytes result;

       for( size_t index = 0; index != buffer_length; index++ )
       {
          result.push_back( buffer[ index ] );
       }

       return result;
    }

EDIT:

Thanks @Michael for catching the realloc. I've been mucking around with the implementation and missed it; still no excuse before posting it.

3
What is the actual problem? That it does not uncompress anything greater than 2048 bytes or less than? - slugonamission
The realloc() is unnecessary if you're doubling buffer_length and jumping back into calloc(). What if buffer_length is changed by uncompress in the error case? Would doubling be the correct thing to do? Perhaps you should use a different value to capture the length of the uncompressed data to preserve the buffer_length. - brandx
@brandx Thanks for the suggestion of uncompress alteration of buffer_length, but I've checked this and its not the case. - Ben Crowhurst
You still appear to be having 2 calloc's in a row when status==Z_BUF_ERROR. Couldn't the initial one be moved out of the do {} while ? - Michael
@Michael daaahhh that'll be the rum. - Ben Crowhurst

3 Answers

1
votes

I got it.

int status

is defined inside and outside of the loop. The Lesson here is never drink & develop.

0
votes

From the zlib manual: "In the case where there is not enough room, uncompress() will fill the output buffer with the uncompressed data up to that point."

I.e, up to 1024 bytes have already been uncompressed, then you get Z_BUF_ERROR and double the buffer size giving you room for 2048 bytes, and once you've uncompressed the second time you've got a total of up to 3072 bytes of uncompressed data.

Also, it looks like you're unnecessarily doing a calloc right after realloc when you get Z_BUF_ERROR.

0
votes

I find nothing apparent that is wrong with your code. You may be mis-predicting the length of your uncompressed data. uncompress() will only return Z_OK if it has decompressed a complete zlib stream and the check value of the uncompressed data matched the check value at the end of the stream.