是的,这是一个错误。
实际上是正确的,如果
inflate()不返回
Z_STREAM_END,则说明您还没有完成通货膨胀。
inflateEnd()返回
Z_OK实际上并没有多大意义,只是返回了一个有效的状态并能够释放内存。
因此
inflate()必须最终返回,
Z_STREAM_END然后才能声明成功。但是,
Z_BUF_ERROR这不是放弃的理由。在这种情况下,您只需
inflate()使用更多的输入或更多的输出空间再次调用即可。然后您将得到
Z_STREAM_END。
从zlib.h中的文档中:
更新:
由于那里有许多错误代码,下面是实现所需方法的正确代码。该代码处理不完整的gzip流,串联的gzip流和非常大的gzip流。对于非常大的gzip流,当编译为64位可执行文件时,中的
unsigned长度
z_stream不够大。
NSUInteger是64位,而是
unsigned32位。在这种情况下,您必须循环输入才能将其提供给
inflate()。
本示例仅返回
nil任何错误。
return nil;如果需要更高级的错误处理,请在每个注释后的注释中注明错误的性质。
- (NSData *) gzipInflate{ z_stream strm; // Initialize input strm.next_in = (Bytef *)[self bytes]; NSUInteger left = [self length]; // input left to decompress if (left == 0) return nil; // incomplete gzip stream // Create starting space for output (guess double the input size, will grow // if needed -- in an extreme case, could end up needing more than 1000 // times the input size) NSUInteger space = left << 1; if (space < left) space = NSUIntegerMax; NSMutableData *decompressed = [NSMutableData dataWithLength: space]; space = [decompressed length]; // Initialize output strm.next_out = (Bytef *)[decompressed mutableBytes]; NSUInteger have = 0; // output generated so far // Set up for gzip decoding strm.avail_in = 0; strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.opaque = Z_NULL; int status = inflateInit2(&strm, (15+16)); if (status != Z_OK) return nil; // out of memory // Decompress all of self do { // Allow for concatenated gzip streams (per RFC 1952) if (status == Z_STREAM_END) (void)inflateReset(&strm); // Provide input for inflate if (strm.avail_in == 0) { strm.avail_in = left > UINT_MAX ? UINT_MAX : (unsigned)left; left -= strm.avail_in; } // Decompress the available input do { // Allocate more output space if none left if (space == have) { // Double space, handle overflow space <<= 1; if (space < have) { space = NSUIntegerMax; if (space == have) { // space was already maxed out! (void)inflateEnd(&strm); return nil; // output exceeds integer size } } // Increase space [decompressed setLength: space]; space = [decompressed length]; // Update output pointer (might have moved) strm.next_out = (Bytef *)[decompressed mutableBytes] + have; } // Provide output space for inflate strm.avail_out = space - have > UINT_MAX ? UINT_MAX : (unsigned)(space - have); have += strm.avail_out; // Inflate and update the decompressed size status = inflate (&strm, Z_SYNC_FLUSH); have -= strm.avail_out; // Bail out if any errors if (status != Z_OK && status != Z_BUF_ERROR && status != Z_STREAM_END) { (void)inflateEnd(&strm); return nil; // invalid gzip stream } // Repeat until all output is generated from provided input (note // that even if strm.avail_in is zero, there may still be pending // output -- we're not done until the output buffer isn't filled) } while (strm.avail_out == 0); // Continue until all input consumed } while (left || strm.avail_in); // Free the memory allocated by inflateInit2() (void)inflateEnd(&strm); // Verify that the input is a valid gzip stream if (status != Z_STREAM_END) return nil; // incomplete gzip stream // Set the actual length and return the decompressed data [decompressed setLength: have]; return decompressed;}


