2008-10-23 8 views
30

¿Hay una API de compresión disponible para usar en el iPhone? Estamos creando algunos servicios web RESTful para nuestra aplicación de iPhone con los que hablar, pero queremos comprimir al menos algunas de las conversaciones por eficiencia.API de compresión en el iPhone

No me importa cuál es el formato (ZIP, LHA, lo que sea), y no es necesario que sea seguro.

Algunos encuestados han señalado que el servidor puede comprimir su salida, y el iPhone puede consumir eso. El escenario que tenemos es exactamente el inverso. Publicaremos el contenido comprimido en el servicio web. No nos preocupa que la compresión vaya hacia otro lado.

+1

Véase también [Cómo comprimir carpetas en iPhone SDK?] (Http://stackoverflow.com/questions/8150185/how-to-zip-folders-in-iphone-sdk) y [ Obj-C, zip libary que se comprime y descomprime, con protección de contraseña?] (Http://stackoverflow.com/questions/8313571/obj-c-zip-libary-which-will-zip-and-unzip-with- protección con contraseña) – bobobobo

Respuesta

12

zlib y bzip2 están disponibles. Y siempre puede agregar otros, siempre que (generalmente) compilen bajo OS X.

bzip2 es una mejor opción para archivos de menor tamaño, pero requiere mucha más potencia de CPU para comprimir y descomprimir.

Además, como está hablando con un servicio web, es posible que no tenga que hacer mucho. NSURLRequest acepta la codificación gzip de forma transparente en las respuestas del servidor.

+1

En realidad, bzip2 requiere más memoria, luego un poco más de CPU, por lo que iría con gzip/deflate (zlib). –

+0

No nos preocupa la compresión proveniente del servidor. Nos preocupa que la compresión vaya al servidor. He editado mi pregunta para reflejar esto. –

+1

Parece que bzip2 está disponible en el dispositivo, pero faltan los encabezados. Aparentemente, algunas aplicaciones fueron rechazadas al usar estas API "privadas" ... – hanno

1

Creo que zlib está disponible en el teléfono.

0

NSURL dice que admite la codificación gzip, por lo que no debería tener que hacer nada más que hacer que su servicio web RESTful devuelva contenido codificado gzip cuando corresponda. Toda la decodificación se hará debajo de las cubiertas.

+1

El problema es que necesitamos codificar nuestros POST, no nuestros GET. –

+1

@Gregory Hinley: 'NSMutableURLRequest * req; [req setHTTPMethod: @ "POST"]; ' –

+0

@ JeremyW.Sherman no maneja el POST en absoluto. Verifiqué esto trabajando en un proyecto. NSURLRequest solo se ocupa de la descarga. https://github.com/AFNetworking/AFNetworking/wiki/AFNetworking-FAQ#how-do-i-use-gzip-compression-with-afnetworking https://github.com/mattt/Godzippa – jpswain

43

Si almacena los datos de las conversaciones en un objeto NSData, los usuarios de la wiki de CocoaDev han publicado un NSData category que agrega compresión/descompresión gzip y zlib como métodos simples. Estos me han funcionado bien en my iPhone application.

Como el enlace anterior se ha extinguido mientras la wiki de CocoaDev se está moviendo a un nuevo host, he reproducido esta categoría en su totalidad a continuación.

Interfaz:

@interface NSData (NSDataExtension) 

// Returns range [start, null byte), or (NSNotFound, 0). 
- (NSRange) rangeOfNullTerminatedBytesFrom:(int)start; 

// Canonical Base32 encoding/decoding. 
+ (NSData *) dataWithBase32String:(NSString *)base32; 
- (NSString *) base32String; 

// COBS is an encoding that eliminates 0x00. 
- (NSData *) encodeCOBS; 
- (NSData *) decodeCOBS; 

// ZLIB 
- (NSData *) zlibInflate; 
- (NSData *) zlibDeflate; 

// GZIP 
- (NSData *) gzipInflate; 
- (NSData *) gzipDeflate; 

//CRC32 
- (unsigned int)crc32; 

// Hash 
- (NSData*) md5Digest; 
- (NSString*) md5DigestString; 
- (NSData*) sha1Digest; 
- (NSString*) sha1DigestString; 
- (NSData*) ripemd160Digest; 
- (NSString*) ripemd160DigestString; 

@end 

Implementación:

#import "NSData+CocoaDevUsersAdditions.h" 
#include <zlib.h> 
#include <openssl/md5.h> 
#include <openssl/sha.h> 
#include <openssl/ripemd.h> 


@implementation NSData (NSDataExtension) 

// Returns range [start, null byte), or (NSNotFound, 0). 
- (NSRange) rangeOfNullTerminatedBytesFrom:(int)start 
{ 
    const Byte *pdata = [self bytes]; 
    int len = [self length]; 
    if (start < len) 
    { 
     const Byte *end = memchr (pdata + start, 0x00, len - start); 
     if (end != NULL) return NSMakeRange (start, end - (pdata + start)); 
    } 
    return NSMakeRange (NSNotFound, 0); 
} 

+ (NSData *) dataWithBase32String:(NSString *)encoded 
{ 
    /* First valid character that can be indexed in decode lookup table */ 
    static int charDigitsBase = '2'; 

    /* Lookup table used to decode() characters in encoded strings */ 
    static int charDigits[] = 
    { 26,27,28,29,30,31,-1,-1,-1,-1,-1,-1,-1,-1 // 23456789:;<=>? 
     ,-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14 // @ABCDEFGHIJKLMNO 
     ,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1 // PQRSTUVWXYZ[\]^_ 
     ,-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14 // `abcdefghijklmno 
     ,15,16,17,18,19,20,21,22,23,24,25    // pqrstuvwxyz 
    }; 

    if (! [encoded canBeConvertedToEncoding:NSASCIIStringEncoding]) return nil; 
    const char *chars = [encoded cStringUsingEncoding:NSASCIIStringEncoding]; // avoids using characterAtIndex. 
    int charsLen = [encoded lengthOfBytesUsingEncoding:NSASCIIStringEncoding]; 

    // Note that the code below could detect non canonical Base32 length within the loop. However canonical Base32 length can be tested before entering the loop. 
    // A canonical Base32 length modulo 8 cannot be: 
    // 1 (aborts discarding 5 bits at STEP n=0 which produces no byte), 
    // 3 (aborts discarding 7 bits at STEP n=2 which produces no byte), 
    // 6 (aborts discarding 6 bits at STEP n=1 which produces no byte). 
    switch (charsLen & 7) { // test the length of last subblock 
     case 1: // 5 bits in subblock: 0 useful bits but 5 discarded 
     case 3: // 15 bits in subblock: 8 useful bits but 7 discarded 
     case 6: // 30 bits in subblock: 24 useful bits but 6 discarded 
      return nil; // non-canonical length 
    } 
    int charDigitsLen = sizeof(charDigits); 
    int bytesLen = (charsLen * 5) >> 3; 
    Byte bytes[bytesLen]; 
    int bytesOffset = 0, charsOffset = 0; 
    // Also the code below does test that other discarded bits 
    // (1 to 4 bits at end) are effectively 0. 
    while (charsLen > 0) 
    { 
     int digit, lastDigit; 
     // STEP n = 0: Read the 1st Char in a 8-Chars subblock 
     // Leave 5 bits, asserting there's another encoding Char 
     if ((digit = (int)chars[charsOffset] - charDigitsBase) < 0 || digit >= charDigitsLen || (digit = charDigits[digit]) == -1) 
      return nil; // invalid character 
     lastDigit = digit << 3; 
     // STEP n = 5: Read the 2nd Char in a 8-Chars subblock 
     // Insert 3 bits, leave 2 bits, possibly trailing if no more Char 
     if ((digit = (int)chars[charsOffset + 1] - charDigitsBase) < 0 || digit >= charDigitsLen || (digit = charDigits[digit]) == -1) 
      return nil; // invalid character 
     bytes[bytesOffset] = (Byte)((digit >> 2) | lastDigit); 
     lastDigit = (digit & 3) << 6; 
     if (charsLen == 2) { 
      if (lastDigit != 0) return nil; // non-canonical end 
      break; // discard the 2 trailing null bits 
     } 
     // STEP n = 2: Read the 3rd Char in a 8-Chars subblock 
     // Leave 7 bits, asserting there's another encoding Char 
     if ((digit = (int)chars[charsOffset + 2] - charDigitsBase) < 0 || digit >= charDigitsLen || (digit = charDigits[digit]) == -1) 
      return nil; // invalid character 
     lastDigit |= (Byte)(digit << 1); 
     // STEP n = 7: Read the 4th Char in a 8-chars Subblock 
     // Insert 1 bit, leave 4 bits, possibly trailing if no more Char 
     if ((digit = (int)chars[charsOffset + 3] - charDigitsBase) < 0 || digit >= charDigitsLen || (digit = charDigits[digit]) == -1) 
      return nil; // invalid character 
     bytes[bytesOffset + 1] = (Byte)((digit >> 4) | lastDigit); 
     lastDigit = (Byte)((digit & 15) << 4); 
     if (charsLen == 4) { 
      if (lastDigit != 0) return nil; // non-canonical end 
      break; // discard the 4 trailing null bits 
     } 
     // STEP n = 4: Read the 5th Char in a 8-Chars subblock 
     // Insert 4 bits, leave 1 bit, possibly trailing if no more Char 
     if ((digit = (int)chars[charsOffset + 4] - charDigitsBase) < 0 || digit >= charDigitsLen || (digit = charDigits[digit]) == -1) 
      return nil; // invalid character 
     bytes[bytesOffset + 2] = (Byte)((digit >> 1) | lastDigit); 
     lastDigit = (Byte)((digit & 1) << 7); 
     if (charsLen == 5) { 
      if (lastDigit != 0) return nil; // non-canonical end 
      break; // discard the 1 trailing null bit 
     } 
     // STEP n = 1: Read the 6th Char in a 8-Chars subblock 
     // Leave 6 bits, asserting there's another encoding Char 
     if ((digit = (int)chars[charsOffset + 5] - charDigitsBase) < 0 || digit >= charDigitsLen || (digit = charDigits[digit]) == -1) 
      return nil; // invalid character 
     lastDigit |= (Byte)(digit << 2); 
     // STEP n = 6: Read the 7th Char in a 8-Chars subblock 
     // Insert 2 bits, leave 3 bits, possibly trailing if no more Char 
     if ((digit = (int)chars[charsOffset + 6] - charDigitsBase) < 0 || digit >= charDigitsLen || (digit = charDigits[digit]) == -1) 
      return nil; // invalid character 
     bytes[bytesOffset + 3] = (Byte)((digit >> 3) | lastDigit); 
     lastDigit = (Byte)((digit & 7) << 5); 
     if (charsLen == 7) { 
      if (lastDigit != 0) return nil; // non-canonical end 
      break; // discard the 3 trailing null bits 
     } 
     // STEP n = 3: Read the 8th Char in a 8-Chars subblock 
     // Insert 5 bits, leave 0 bit, next encoding Char may not exist 
     if ((digit = (int)chars[charsOffset + 7] - charDigitsBase) < 0 || digit >= charDigitsLen || (digit = charDigits[digit]) == -1) 
      return nil; // invalid character 
     bytes[bytesOffset + 4] = (Byte)(digit | lastDigit); 
     //// This point is always reached for chars.length multiple of 8 
     charsOffset += 8; 
     bytesOffset += 5; 
     charsLen -= 8; 
    } 
    // On loop exit, discard the n trailing null bits 
    return [NSData dataWithBytes:bytes length:sizeof(bytes)]; 
} 

- (NSString *) base32String 
{ 
    /* Lookup table used to canonically encode() groups of data bits */ 
    static char canonicalChars[] = 
    { 'A','B','C','D','E','F','G','H','I','J','K','L','M' // 00..12 
     ,'N','O','P','Q','R','S','T','U','V','W','X','Y','Z' // 13..25 
     ,'2','3','4','5','6','7'        // 26..31 
    }; 
    const Byte *bytes = [self bytes]; 
    int bytesOffset = 0, bytesLen = [self length]; 
    int charsOffset = 0, charsLen = ((bytesLen << 3) + 4)/5; 
    char chars[charsLen]; 
    while (bytesLen != 0) { 
     int digit, lastDigit; 
     // INVARIANTS FOR EACH STEP n in [0..5[; digit in [0..31[; 
     // The remaining n bits are already aligned on top positions 
     // of the 5 least bits of digit, the other bits are 0. 
     ////// STEP n = 0: insert new 5 bits, leave 3 bits 
     digit = bytes[bytesOffset] & 255; 
     chars[charsOffset] = canonicalChars[digit >> 3]; 
     lastDigit = (digit & 7) << 2; 
     if (bytesLen == 1) { // put the last 3 bits 
      chars[charsOffset + 1] = canonicalChars[lastDigit]; 
      break; 
     } 
     ////// STEP n = 3: insert 2 new bits, then 5 bits, leave 1 bit 
     digit = bytes[bytesOffset + 1] & 255; 
     chars[charsOffset + 1] = canonicalChars[(digit >> 6) | lastDigit]; 
     chars[charsOffset + 2] = canonicalChars[(digit >> 1) & 31]; 
     lastDigit = (digit & 1) << 4; 
     if (bytesLen == 2) { // put the last 1 bit 
      chars[charsOffset + 3] = canonicalChars[lastDigit]; 
      break; 
     } 
     ////// STEP n = 1: insert 4 new bits, leave 4 bit 
     digit = bytes[bytesOffset + 2] & 255; 
     chars[charsOffset + 3] = canonicalChars[(digit >> 4) | lastDigit]; 
     lastDigit = (digit & 15) << 1; 
     if (bytesLen == 3) { // put the last 1 bits 
      chars[charsOffset + 4] = canonicalChars[lastDigit]; 
      break; 
     } 
     ////// STEP n = 4: insert 1 new bit, then 5 bits, leave 2 bits 
     digit = bytes[bytesOffset + 3] & 255; 
     chars[charsOffset + 4] = canonicalChars[(digit >> 7) | lastDigit]; 
     chars[charsOffset + 5] = canonicalChars[(digit >> 2) & 31]; 
     lastDigit = (digit & 3) << 3; 
     if (bytesLen == 4) { // put the last 2 bits 
      chars[charsOffset + 6] = canonicalChars[lastDigit]; 
      break; 
     } 
     ////// STEP n = 2: insert 3 new bits, then 5 bits, leave 0 bit 
     digit = bytes[bytesOffset + 4] & 255; 
     chars[charsOffset + 6] = canonicalChars[(digit >> 5) | lastDigit]; 
     chars[charsOffset + 7] = canonicalChars[digit & 31]; 
     //// This point is always reached for bytes.length multiple of 5 
     bytesOffset += 5; 
     charsOffset += 8; 
     bytesLen -= 5; 
    } 
    return [NSString stringWithCString:chars length:sizeof(chars)]; 
} 

#define FinishBlock(X) \ 
(*code_ptr = (X), \ 
code_ptr = dst++, \ 
code = 0x01) 

- (NSData *) encodeCOBS 
{ 
    if ([self length] == 0) return self; 

    NSMutableData *encoded = [NSMutableData dataWithLength:([self length] + [self length]/254 + 1)]; 
    unsigned char *dst = [encoded mutableBytes]; 
    const unsigned char *ptr = [self bytes]; 
    unsigned long length = [self length]; 
    const unsigned char *end = ptr + length; 
    unsigned char *code_ptr = dst++; 
    unsigned char code = 0x01; 
    while (ptr < end) 
    { 
     if (*ptr == 0) FinishBlock(code); 
     else 
     { 
      *dst++ = *ptr; 
      code++; 
      if (code == 0xFF) FinishBlock(code); 
     } 
     ptr++; 
    } 
    FinishBlock(code); 

    [encoded setLength:((Byte *)dst - (Byte *)[encoded mutableBytes])]; 
    return [NSData dataWithData:encoded]; 
} 

- (NSData *) decodeCOBS 
{ 
    if ([self length] == 0) return self; 

    const Byte *ptr = [self bytes]; 
    unsigned length = [self length]; 
    NSMutableData *decoded = [NSMutableData dataWithLength:length]; 
    Byte *dst = [decoded mutableBytes]; 
    Byte *basedst = dst; 

    const unsigned char *end = ptr + length; 
    while (ptr < end) 
    { 
     int i, code = *ptr++; 
     for (i=1; i<code; i++) *dst++ = *ptr++; 
     if (code < 0xFF) *dst++ = 0; 
    } 

    [decoded setLength:(dst - basedst)]; 
    return [NSData dataWithData:decoded]; 
} 

- (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) 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; 
} 

- (NSData *)zlibDeflate 
{ 
    if ([self length] == 0) return self; 

    z_stream strm; 

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

    // Compresssion Levels: 
    // Z_NO_COMPRESSION 
    // Z_BEST_SPEED 
    // Z_BEST_COMPRESSION 
    // Z_DEFAULT_COMPRESSION 

    if (deflateInit(&strm, Z_DEFAULT_COMPRESSION) != Z_OK) return nil; 

    NSMutableData *compressed = [NSMutableData dataWithLength:16384]; // 16K chuncks for expansion 

    do { 

     if (strm.total_out >= [compressed length]) 
      [compressed increaseLengthBy: 16384]; 

     strm.next_out = [compressed mutableBytes] + strm.total_out; 
     strm.avail_out = [compressed length] - strm.total_out; 

     deflate(&strm, Z_FINISH); 

    } while (strm.avail_out == 0); 

    deflateEnd(&strm); 

    [compressed setLength: strm.total_out]; 
    return [NSData dataWithData: compressed]; 
} 

- (NSData *)gzipInflate 
{ 
    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 (inflateInit2(&strm, (15+32)) != 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) 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; 
} 

- (NSData *)gzipDeflate 
{ 
    if ([self length] == 0) return self; 

    z_stream strm; 

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

    // Compresssion Levels: 
    // Z_NO_COMPRESSION 
    // Z_BEST_SPEED 
    // Z_BEST_COMPRESSION 
    // Z_DEFAULT_COMPRESSION 

    if (deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, (15+16), 8, Z_DEFAULT_STRATEGY) != Z_OK) return nil; 

    NSMutableData *compressed = [NSMutableData dataWithLength:16384]; // 16K chunks for expansion 

    do { 

     if (strm.total_out >= [compressed length]) 
      [compressed increaseLengthBy: 16384]; 

     strm.next_out = [compressed mutableBytes] + strm.total_out; 
     strm.avail_out = [compressed length] - strm.total_out; 

     deflate(&strm, Z_FINISH); 

    } while (strm.avail_out == 0); 

    deflateEnd(&strm); 

    [compressed setLength: strm.total_out]; 
    return [NSData dataWithData:compressed]; 
} 

// --------------------------------CRC32------------------------------- 
static const unsigned long crc32table[] = 
{ 
    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 
    0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 
    0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 
    0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 
    0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 
    0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 
    0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 
    0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 
    0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 
    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 
    0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 
    0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 
    0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 
    0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 
    0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 
    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 
    0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 
    0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 
    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 
    0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 
    0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 
    0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 
    0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 
    0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 
    0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 
    0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 
    0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 
    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 
    0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 
    0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 
    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 
    0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d 
}; 

- (unsigned int)crc32 
{ 
    unsigned int crcval; 
    unsigned int x, y; 
    const void  *bytes; 
    unsigned int max; 

    bytes = [self bytes]; 
    max = [self length]; 
    crcval = 0xffffffff; 
    for (x = 0, y = max; x < y; x++) { 
     crcval = ((crcval >> 8) & 0x00ffffff)^crc32table[(crcval^(*((unsigned char *)bytes + x))) & 0xff]; 
    } 

    return crcval^0xffffffff; 
} 

// Hash function, by [[DamienBob]] 

#define HEComputeDigest(method)      \ 
method##_CTX ctx;        \ 
unsigned char digest[method##_DIGEST_LENGTH];  \ 
method##_Init(&ctx);       \ 
method##_Update(&ctx, [self bytes], [self length]);  \ 
method##_Final(digest, &ctx); 

#define HEComputeDigestNSData(method)    \ 
HEComputeDigest(method)      \ 
return [NSData dataWithBytes:digest length:method##_DIGEST_LENGTH]; 

#define HEComputeDigestNSString(method)    \ 
static char __HEHexDigits[] = "abcdef";  \ 
unsigned char digestString[2*method##_DIGEST_LENGTH];\ 
unsigned int i;         \ 
HEComputeDigest(method)      \ 
for(i=0; i<method##_DIGEST_LENGTH; i++) {    \ 
    digestString[2*i] = __HEHexDigits[digest[i] >> 4]; \ 
    digestString[2*i+1] = __HEHexDigits[digest[i] & 0x0f];\ 
}           \ 
return [NSString stringWithCString:(char *)digestString length:2*method##_DIGEST_LENGTH]; 

#define SHA1_CTX    SHA_CTX 
#define SHA1_DIGEST_LENGTH  SHA_DIGEST_LENGTH 

- (NSData*) md5Digest 
{ 
    HEComputeDigestNSData(MD5); 
} 

- (NSString*) md5DigestString 
{ 
    HEComputeDigestNSString(MD5); 
} 

- (NSData*) sha1Digest 
{ 
    HEComputeDigestNSData(SHA1); 
} 

- (NSString*) sha1DigestString 
{ 
    HEComputeDigestNSString(SHA1); 
} 

- (NSData*) ripemd160Digest 
{ 
    HEComputeDigestNSData(RIPEMD160); 
} 

- (NSString*) ripemd160DigestString 
{ 
    HEComputeDigestNSString(RIPEMD160); 
} 

@end 
+0

¡Impresionante! ¡Gracias! –

+0

@Brad Larson NSData categoría de enlace no funciona (404 no encontrado). Por favor actualice ... –

+0

@Pranav - Gracias por informarme. He agregado el código fuente completo de la memoria caché de Google del sitio en el cuerpo de mi respuesta. –

4

Si sólo tiene datos comprimidos y saber el tamaño no comprimido que puede utilizar:

#import "zlib.h" 


int datal = [zipedData length]; 
Bytef *buffer[uncompressedSize]; 
Bytef *dataa[datal]; 

[zipedData getBytes:dataa]; 

Long *ld; 

uLong sl = datal; 
*ld = uncompressedSize; 
if(uncompress(buffer, ld, dataa, sl) == Z_OK) 
{ 
NSData *uncompressedData = [NSData dataWithBytes:buffer length:uncompressedSize]; 
NSString *txtFile = [[NSString alloc] initWithData:uncompressedData encoding:NSUTF8StringEncoding]; 
} 
1

Objective-Zip es otra opción. Vea estos excelentes instructions.

Nota: tuve que convertir el código fuente para usar ARC usando XCode-> Edit-> Refactor-> Convert to Objective C ARC.

6

La compresión de compilación incorporada de Apple ya está disponible para iOS 9. A continuación se muestra un ejemplo corto de compression_encode_buffer para comprimir NSData.

@import Compression; 

NSData *theData = [NSData dataWithContentsOfFile:[<some file> path]]; 
size_t theDataSize = [theData length]; 
const uint8_t *buf = (const uint8_t *)[theData bytes]; 
uint8_t *destBuf = malloc(sizeof(uint8_t) * theDataSize); 
size_t compressedSize = compression_encode_buffer(destBuf, theDataSize, buf, theDataSize, NULL, COMPRESSION_LZFSE); 
self.<NSData item> = [NSData dataWithBytes:destBuf length:compressedSize]; 

NSLog(@"originalsize:%zu compressed:%zu", theDataSize, compressedSize); 
free(destBuf); 

Un número de diferentes algoritmos están disponibles:

  • LZMA
  • LZ4
  • ZLIB
  • LZFSE

de compresión en bloque o compresión corriente son a la vez compatibles.

Ver https://developer.apple.com/library/mac/documentation/Performance/Reference/Compression/