zLib на iPhone, остановитесь сначала BLOCK

Я пытаюсь вызвать iPhone zLib, чтобы распаковать поток zlib с нашего HTTP-сервера, но код всегда останавливается после завершения первого блока 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) Данные, которые я получаю с сервера, выглядят примерно так (если они распакованы). Поток был сжат с помощью класса zlib C # 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 всегда прерывает выполнение во второй раз.

    + (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   }

person cedric    schedule 09.04.2010    source источник


Ответы (1)


У меня была эта проблема, и я разобрался с ней. Код немного ошибочен, так как он ломается, если возвращается Z_BUF_ERROR, но при чтении zlib Documentation оказывается что Z_BUF_ERROR не должен проверяться на инфляцию, так как он может быть брошен, даже если результат в порядке.

Таким образом, сработало изменение кода:

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

Надеюсь, что это работает для вас.

РЕДАКТИРОВАТЬ: (18 июня 2011 г.)
Вот полный метод инфляции, как и требовалось. Он реализован как категория в 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

Карлос

person Carlos P    schedule 05.07.2010
comment
Привет, Карлос! Очень приятно видеть, что у кого-то наконец-то все работает. Однако я внес предложенное вами изменение, оно тоже не работает. Боюсь, в моем коде есть другие проблемы. Итак, вы можете прикрепить сюда весь код инфляции? Спасибо! Седрик - person cedric; 05.08.2010
comment
Привет, Седрик, конечно, я постараюсь не забыть выкопать его - person Carlos P; 07.11.2010
comment
Как и обещал, выкопал код; Постараюсь выложить как еще один ответ. Если это вам поможет, возможно, вы отметите это как правильное. - person Carlos P; 19.06.2011