Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
446 views
in Technique[技术] by (71.8m points)

c - Why is ZLib not appending the adler32 and length fields to compressed data?

I've got a problem with my usage of the ZLib API. My data is correctly compressed and decompressed again, but the ::inflate() (decompression) side is never returning with Z_STREAM_END, only Z_OK (which is not how it should be, according to the docs and the ZLib source code).

Here's what I'm doing to compress:

// (set up a `z_stream` with `data_type` as `Z_BINARY`)
call `::deflate(..., Z_NO_FLUSH)` to compress chunks until no more input left
call `::deflate(..., Z_FINISH)` until it returns `Z_STREAM_END` (it does!)

Later, I'm doing the same with ::inflate():

// (set up a `z_stream` with `data_type` as `Z_BINARY`)
call `::inflate(..., Z_NO_FLUSH)` to decompress chunks until no more input left
call `::inflate(..., Z_FINISH)` until it returns `Z_STREAM_END` (never happens).

What happens is that ::inflate(..., Z_NO_FLUSH) consumes all input and produces the full decompressed stream(!), while still only returning Z_OK.


At this point, z_stream::state is still CHECK (inflate.c, line #1198 - wants to read 32 bits for adler32 checksum), then z_stream::state should be set to LENGTH (inflate.c, line #1221 - want to read another 32 bits for stream length) and finally z_stream::state should be set to DONE which gives the expected Z_STREAM_END return value (inflate.c, line #1235).

However, the 32 bits for the adler32 checksum and the 32 bits for the stream length are never appended by ::deflate(). Am I missing something or using ZLib wrongly?


UPDATE: as requested, the compression code in detail

// Initialization
this->stream.msg = nullptr;
this->stream.state = nullptr;
this->stream.zalloc = &allocate; // delegates to malloc() (Z_SOLO)
this->stream.zfree = &free; // delegates to free() (Z_SOLO)
this->stream.data_type = Z_BINARY;

int result = ::deflateInit(&this->stream, Z_DEFAULT_COMPRESSION);
// error handling performed here

// ...

while(input_data_available) {

  this->stream.next_in = uncompressedBuffer;
  this->stream.avail_in = static_cast<uInt>(uncompressedByteCount);
  this->stream.next_out = outputBuffer;
  this->stream.avail_out = static_cast<uInt>(outputByteCount);

  int result = ::deflate(&this->stream, Z_NO_FLUSH);
  // error handling performed here
  
}

do {

  this->stream.next_in = nullptr;
  this->stream.avail_in = 0;
  this->stream.next_out = outputBuffer;
  this->stream.avail_out = static_cast<uInt>(outputByteCount);

  int result = ::deflate(&this->stream, Z_FINISH);
  // error handling performed here

} while(this->stream.avail_out == 0);

assert(result == Z_STREAM_END);

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The code that you linked has:

int result = ::deflateInit2(
&this->stream, level, Z_DEFLATED, -MAX_WBITS, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY
);

The -MAX_WBITS requests a raw deflate stream, with no header or trailer. The reason you are not getting a trailer is because you requested that there not be a trailer.

As an aside, your question talks about an Adler-32 field and a length field. Those never go together. Either you request the zlib format (with MAX_WBITS), which has only an Adler-32 in the trailer, or you request the gzip format (with MAX_WBITS+16), which has a CRC-32 and a length field.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...