0

我正在尝试调用 iPhone zLib 从我们基于 HTTP 的服务器解压缩 zlib 流,但代码总是在完成第一个 zlib 块后停止。

显然,iPhone SDK 使用的是标准开放的 Zlib。我怀疑inflateInit2的参数在这里不合适。

我花了很多时间阅读 zlib 手册,但这并没有多大帮助。

这是详细信息,感谢您的帮助。

(1)HTTP请求:

NSURL *url = [NSURL URLWithString:@"http://192.168.0.98:82/WIC?query=getcontacts&PIN=12345678&compression=Y"]; 

(2) 我从服务器得到的数据是这样的(如果解压的话)。该流由 C# zlib 类DeflateStream压缩:

$REC_TYPE=SYS
Status=OK
Message=OK
SetID=
IsLast=Y
StartIndex=0
LastIndex=6
EOR

……

$REC_TYPE=CONTACTSDISTLIST
ID=2
Name=CTU+L%2EA%2E
OnCallEnabled=Y
OnCallMinUsers=1
OnCallEditRight=
OnCallEditDLRight=D
Fields=
CL=
OnCallStatus=
EOR

(3) 但是,我只会得到第一个 Block。iPhone 上的解压代码(从此处某处的代码段复制)如下。 第 23~38 行之间的循环总是会中断第二次执行。

    + (NSData *) uncompress: (NSData*) data
    {
 1    if ([data length] == 0) return nil;
 2   NSInteger length = [data length];
 3    unsigned full_length = length;
 4    unsigned half_length =length/ 2;

 5    NSMutableData *decompressed = [NSMutableData dataWithLength: 5*full_length + half_length];
 6    BOOL done = NO;
 7    int status;

 8   z_stream strm;
 9    length=length-4;
 10    void* bytes= malloc(length);
 11    NSRange range;
 12    range.location=4;
 13   range.length=length;
 14    [data getBytes: bytes range: range];
 15    strm.next_in = bytes;
 16    strm.avail_in = length;
 17    strm.total_out = 0;
 18    strm.zalloc = Z_NULL;
 19   strm.zfree = Z_NULL;
 20    strm.data_type= Z_BINARY;
 21  // if (inflateInit(&strm) != Z_OK) return nil;

 22    if (inflateInit2(&strm, (-15)) != Z_OK) return nil; //It won't work if change -15 to positive numbers.
 23   while (!done)
 24    {
 25     // Make sure we have enough room and reset the lengths.
 26     if (strm.total_out >= [decompressed length])
 27      [decompressed increaseLengthBy: half_length];
 28     strm.next_out = [decompressed mutableBytes] + strm.total_out;
 29     strm.avail_out = [decompressed length] - strm.total_out;
 30     
 31     // Inflate another chunk.
 32     status = inflate (&strm, Z_SYNC_FLUSH); //Z_SYNC_FLUSH-->Z_BLOCK, won't work either 
 33     if (status == Z_STREAM_END){
 34      
 35      done = YES;
 36     }
 37     else if (status != Z_OK) break;
 38    }

 39    if (inflateEnd (&strm) != Z_OK) return nil;

 40    // Set real length.
 41    if (done)
 42    {
 43     [decompressed setLength: strm.total_out];
 44     return [NSData dataWithData: decompressed];
 45    }
 46    else return nil;
 47   }
4

1 回答 1

1

我遇到了这个问题并解决了。如果返回 Z_BUF_ERROR ,代码会出现一些问题,因为它会中断,但是在阅读zlib 文档时,结果表明不应该检查 Z_BUF_ERROR 膨胀,因为即使结果输出很好,它也可以被抛出。

更改代码因此有效:

// Inflate another chunk.
        status = inflate (&strm, Z_SYNC_FLUSH);
        if ( (status == Z_STREAM_END) || (status == Z_BUF_ERROR) )
            done = YES;

希望这对你有用。

编辑:(2011 年 6 月 18 日)
根据要求,这是完整的通货膨胀方法。它被实现为 NSData 上的一个类别:

@interface NSData (NSDataExtension)
- (NSData *) zlibInflate;
@end

@implementation NSData (NSDataExtension)
- (NSData *)zlibInflate
{
if ([self length] == 0) return self;

unsigned full_length = [self length];
unsigned half_length = [self length] / 2;

NSMutableData *decompressed = [NSMutableData dataWithLength: full_length + half_length];
BOOL done = NO;
int status;

z_stream strm;
strm.next_in = (Bytef *)[self bytes];
strm.avail_in = [self length];
strm.total_out = 0;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;

if (inflateInit (&strm) != Z_OK) return nil;

while (!done)
{
    // Make sure we have enough room and reset the lengths.
    if (strm.total_out >= [decompressed length])
        [decompressed increaseLengthBy: half_length];
    strm.next_out = [decompressed mutableBytes] + strm.total_out;
    strm.avail_out = [decompressed length] - strm.total_out;

    // Inflate another chunk.
    status = inflate (&strm, Z_SYNC_FLUSH);
    if (
        (status == Z_STREAM_END) || (status == Z_BUF_ERROR) 
        )
        done = YES;
    else if (status != Z_OK) break;
}
if (inflateEnd (&strm) != Z_OK) return nil;

// Set real length.
if (done)
{
    [decompressed setLength: strm.total_out];
    return [NSData dataWithData: decompressed];
}
else return nil;
}
@end

卡洛斯

于 2010-07-05T21:44:34.897 回答