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) ただし、最初のブロックしか取得しません。iPhone で解凍するためのコード (ここのどこかにあるコード片からコピー) は次のとおりです。 23 ~ 38 行目のループは、2 回目の実行で必ず中断します。

    + (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 に答える