2010-04-09 5 views
0

J'essaie d'appeler iPhone zLib pour décompresser le flux zlib à partir de notre serveur HTTP, mais le code s'arrête toujours après avoir terminé le premier bloc zlib.zLib sur iPhone, arrêtez-vous d'abord BLOG

De toute évidence, iPhone SDK utilise le standard Zlib ouvert. Mon doute est que le paramètre pour inflateInit2 n'est pas approprié ici. J'ai passé beaucoup de temps à lire le manuel de zlib, mais ce n'est pas très utile.

Voici les détails, votre aide est appréciée.

(1) la requête HTTP:

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

(2) Les données que je reçois de serveur est quelque chose comme ça (si décompressé). Le flux a été compressé par C# zlib classe 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) Cependant, je n'obtenir le premier bloc. Le code pour la décompression sur iPhone (copié à partir d'une pièce de code from somewhere here) est le suivant. La boucle entre les lignes 23 ~ 38 rompt toujours la seconde exécution.

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

Répondre

1

J'ai eu ce problème et je l'ai résolu. Le code est légèrement bogué car il se casse si Z_BUF_ERROR est retourné, mais en lisant le zlib Documentation il s'avère que Z_BUF_ERROR ne devrait pas être vérifié sur l'inflation, car il peut être lancé même si la sortie résultante est bonne.

Modification du code de travail ainsi effectué:

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

espère que cela fonctionne pour vous.

EDIT: (18e Juin 2011)
Voici la méthode complète d'inflation, tel que demandé. Il est mis en œuvre en tant que catégorie sur 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 

Carlos

+0

Salut, Carlos, Il est très encourageant de voir quelqu'un a finalement obtenu fonctionner. Cependant, j'ai fait le changement que vous avez suggéré, cela ne fonctionne pas non plus. J'ai peur que mon code ait d'autres problèmes. Alors, pouvez-vous joindre le code d'inflation entier ici? Merci! Cedric – cedric

+0

Salut Cedric, bien sûr, je vais essayer de me rappeler de le déterrer –

+0

Comme promis, j'ai creusé le code; Je vais essayer de l'afficher comme une autre réponse. Si cela vous aide, peut-être que vous pourriez marquer comme correct. –